3dmol
Version:
JavaScript/TypeScript molecular visualization library
632 lines (563 loc) • 50.6 kB
HTML
<!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="Author" content="David Koes & 3Dmoljs Contributors"><meta name="Description" content="A modern, object-oriented JavaScript library for visualizing molecular data"><title>Source: utilities.ts</title><!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><style>article ul li{list-style:disc}</style><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="light"><div class="sidebar-container"><div class="sidebar" id="sidebar"><a href="/" class="sidebar-title sidebar-title-anchor">3Dmol.js</a><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="mei5HJjYKLn6aua5Z5PM5"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="$3Dmol.Label.html">Label</a></div><div class="sidebar-section-children"><a href="$3Dmol.StateManager.html">StateManager</a></div><div class="sidebar-section-children"><a href="$3Dmol.UI.html">UI</a></div><div class="sidebar-section-children"><a href="Color.html">Color</a></div><div class="sidebar-section-children"><a href="CustomLinear.html">CustomLinear</a></div><div class="sidebar-section-children"><a href="Cylinder.html">Cylinder</a></div><div class="sidebar-section-children"><a href="GLModel.html">GLModel</a></div><div class="sidebar-section-children"><a href="GLShape.html">GLShape</a></div><div class="sidebar-section-children"><a href="GLShape_GLShape.html">GLShape</a></div><div class="sidebar-section-children"><a href="GLViewer.html">GLViewer</a></div><div class="sidebar-section-children"><a href="GLVolumetricRender.html">GLVolumetricRender</a></div><div class="sidebar-section-children"><a href="Matrix3.html">Matrix3</a></div><div class="sidebar-section-children"><a href="Matrix4.html">Matrix4</a></div><div class="sidebar-section-children"><a href="Quaternion.html">Quaternion</a></div><div class="sidebar-section-children"><a href="ROYGB.html">ROYGB</a></div><div class="sidebar-section-children"><a href="RWB.html">RWB</a></div><div class="sidebar-section-children"><a href="Ray.html">Ray</a></div><div class="sidebar-section-children"><a href="Sinebow.html">Sinebow</a></div><div class="sidebar-section-children"><a href="Sphere.html">Sphere</a></div><div class="sidebar-section-children"><a href="Surface.html">Surface</a></div><div class="sidebar-section-children"><a href="Triangle.html">Triangle</a></div><div class="sidebar-section-children"><a href="Vector2.html">Vector2</a></div><div class="sidebar-section-children"><a href="Vector3.html">Vector3</a></div><div class="sidebar-section-children"><a href="VolumeData.html">VolumeData</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="kv4Yx5z0THf_b8XR4Gje1"><div>Namespaces</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="GLDraw.html">GLDraw</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="ykThSufQWJcKGT1kXzr-A"><div>Tutorials</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="tutorial-code.html">Using 3Dmol within your code</a></div><div class="sidebar-section-children"><a href="tutorial-embeddable.html">Embedding a 3Dmol Viewer</a></div><div class="sidebar-section-children"><a href="tutorial-home.html">3Dmol Tutorials - Home</a></div><div class="sidebar-section-children"><a href="tutorial-learning_environment.html">Active Learning with 3Dmol.js</a></div><div class="sidebar-section-children"><a href="tutorial-url.html">Viewing Molecules with the 3Dmol Server</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="XcP4RUEg6tp7YKHbBVi9E"><div>Interfaces</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="AmbientOcclusionStyle.html">AmbientOcclusionStyle</a></div><div class="sidebar-section-children"><a href="ArrowSpec.html">ArrowSpec</a></div><div class="sidebar-section-children"><a href="AtomSelectionSpec.html">AtomSelectionSpec</a></div><div class="sidebar-section-children"><a href="AtomSpec.html">AtomSpec</a></div><div class="sidebar-section-children"><a href="AtomStyleSpec.html">AtomStyleSpec</a></div><div class="sidebar-section-children"><a href="BondStyle.html">BondStyle</a></div><div class="sidebar-section-children"><a href="BoxSpec.html">BoxSpec</a></div><div class="sidebar-section-children"><a href="CartoonStyleSpec.html">CartoonStyleSpec</a></div><div class="sidebar-section-children"><a href="ClickSphereStyleSpec.html">ClickSphereStyleSpec</a></div><div class="sidebar-section-children"><a href="CrossStyleSpec.html">CrossStyleSpec</a></div><div class="sidebar-section-children"><a href="CurveSpec.html">CurveSpec</a></div><div class="sidebar-section-children"><a href="CustomShapeSpec.html">CustomShapeSpec</a></div><div class="sidebar-section-children"><a href="CylinderSpec.html">CylinderSpec</a></div><div class="sidebar-section-children"><a href="DashedBondSpec.html">DashedBondSpec</a></div><div class="sidebar-section-children"><a href="FogSpec.html">FogSpec</a></div><div class="sidebar-section-children"><a href="IsoSurfaceSpec.html">IsoSurfaceSpec</a></div><div class="sidebar-section-children"><a href="LabelSpec.html">LabelSpec</a></div><div class="sidebar-section-children"><a href="LineSpec.html">LineSpec</a></div><div class="sidebar-section-children"><a href="LineStyleSpec.html">LineStyleSpec</a></div><div class="sidebar-section-children"><a href="OutlineStyle.html">OutlineStyle</a></div><div class="sidebar-section-children"><a href="ParserOptionsSpec.html">ParserOptionsSpec</a></div><div class="sidebar-section-children"><a href="ShapeSpec.html">ShapeSpec</a></div><div class="sidebar-section-children"><a href="SphereSpec.html">SphereSpec</a></div><div class="sidebar-section-children"><a href="SphereStyleSpec.html">SphereStyleSpec</a></div><div class="sidebar-section-children"><a href="StickStyleSpec.html">StickStyleSpec</a></div><div class="sidebar-section-children"><a href="SurfaceStyleSpec.html">SurfaceStyleSpec</a></div><div class="sidebar-section-children"><a href="UnitCellStyleSpec.html">UnitCellStyleSpec</a></div><div class="sidebar-section-children"><a href="ViewStyle.html">ViewStyle</a></div><div class="sidebar-section-children"><a href="ViewerGridSpec.html">ViewerGridSpec</a></div><div class="sidebar-section-children"><a href="ViewerSpec.html">ViewerSpec</a></div><div class="sidebar-section-children"><a href="VolumetricRendererSpec.html">VolumetricRendererSpec</a></div><div class="sidebar-section-children"><a href="WithinSelectionSpec.html">WithinSelectionSpec</a></div><div class="sidebar-section-children"><a href="global.html#XYZ">XYZ</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="jmKnIXRJjdjZ366ci7cdd"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#BCIF">BCIF</a></div><div class="sidebar-section-children"><a href="global.html#CAP">CAP</a></div><div class="sidebar-section-children"><a href="global.html#CDJSON">CDJSON</a></div><div class="sidebar-section-children"><a href="global.html#CIF">CIF</a></div><div class="sidebar-section-children"><a href="global.html#CUBE">CUBE</a></div><div class="sidebar-section-children"><a href="global.html#ColorSpec">ColorSpec</a></div><div class="sidebar-section-children"><a href="global.html#ColorschemeSpec">ColorschemeSpec</a></div><div class="sidebar-section-children"><a href="global.html#GRO">GRO</a></div><div class="sidebar-section-children"><a href="global.html#GradientSpec">GradientSpec</a></div><div class="sidebar-section-children"><a href="global.html#MMTFparser">MMTFparser</a></div><div class="sidebar-section-children"><a href="global.html#MOL2">MOL2</a></div><div class="sidebar-section-children"><a href="global.html#OFFSETS">OFFSETS</a></div><div class="sidebar-section-children"><a href="global.html#PDB">PDB</a></div><div class="sidebar-section-children"><a href="global.html#PQR">PQR</a></div><div class="sidebar-section-children"><a href="global.html#PRMTOP">PRMTOP</a></div><div class="sidebar-section-children"><a href="global.html#SDF">SDF</a></div><div class="sidebar-section-children"><a href="global.html#SurfaceType">SurfaceType</a></div><div class="sidebar-section-children"><a href="global.html#VASP">VASP</a></div><div class="sidebar-section-children"><a href="global.html#XYZ">XYZ</a></div><div class="sidebar-section-children"><a href="global.html#assignPDBBonds">assignPDBBonds</a></div><div class="sidebar-section-children"><a href="global.html#builtinColorSchemes">builtinColorSchemes</a></div><div class="sidebar-section-children"><a href="global.html#builtinGradients">builtinGradients</a></div><div class="sidebar-section-children"><a href="global.html#conversionMatrix3">conversionMatrix3</a></div><div class="sidebar-section-children"><a href="global.html#createViewer">createViewer</a></div><div class="sidebar-section-children"><a href="global.html#createViewerGrid">createViewerGrid</a></div><div class="sidebar-section-children"><a href="global.html#decode">decode</a></div><div class="sidebar-section-children"><a href="global.html#dic">dic</a></div><div class="sidebar-section-children"><a href="global.html#download">download</a></div><div class="sidebar-section-children"><a href="global.html#elementColors">elementColors</a></div><div class="sidebar-section-children"><a href="global.html#get">get</a></div><div class="sidebar-section-children"><a href="global.html#getColorFromStyle">getColorFromStyle</a></div><div class="sidebar-section-children"><a href="global.html#getbin">getbin</a></div><div class="sidebar-section-children"><a href="global.html#parseV3000">parseV3000</a></div><div class="sidebar-section-children"><a href="global.html#setSyncSurface">setSyncSurface</a></div><div class="sidebar-section-children"><a href="global.html#ssColors">ssColors</a></div><div class="sidebar-section-children"><a href="global.html#syncSurface">syncSurface</a></div><div class="sidebar-section-children"><a href="global.html#viewers">viewers</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"><div class="navbar-item"><a id="" href="https://3dmol.org/doc/index.html" target="">Documentation</a></div><div class="navbar-item"><a id="" href="tutorial-home.html" target="">Tutorials</a></div><div class="navbar-item"><a id="" href="https://github.com/3dmol/3Dmol.js" target="_blank">GitHub</a></div></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">utilities.ts</h1></header><article><pre class="prettyprint source lang-js"><code>//a collection of miscellaneous utility functions
import { GLViewer } from "GLViewer";
import { getGradient, Gradient, GradientType } from "./Gradient";
import { VolumeData } from "./VolumeData";
import { builtinColorSchemes, CC, elementColors, htmlColors, Color } from "./colors";
import { IsoSurfaceSpec } from "GLShape";
import { inflate, InflateFunctionOptions, Data } from "pako"
//simplified version of jquery extend
export function extend(obj1, src1) {
for (var key in src1) {
if (src1.hasOwnProperty(key) && src1[key] !== undefined) {
obj1[key] = src1[key];
}
}
return obj1;
};
//deep copy, cannot deal with circular refs; undefined input becomes an empty object
//https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089
export function deepCopy(inObject) {
let outObject, value, key;
if (inObject == undefined) {
return {};
}
if (typeof inObject !== "object" || inObject === null) {
return inObject; // Return the value if inObject is not an object
}
// Create an array or object to hold the values
outObject = Array.isArray(inObject) ? [] : {};
for (key in inObject) {
value = inObject[key];
// Recursively (deep) copy for nested objects, including arrays
outObject[key] = deepCopy(value);
}
return outObject;
};
export function isNumeric(obj) {
var type = typeof (obj);
return (type === "number" || type === "string") &&
!isNaN(obj - parseFloat(obj));
};
export function isEmptyObject(obj: object) {
return Object.keys(obj).length === 0;
};
export type Func = Function|string|undefined|null;
export function makeFunction(callback:Func): Function {
//for py3dmol let users provide callback as string
if (callback && typeof callback === "string") {
/* jshint ignore:start */
callback = eval("(" + callback + ")");
/* jshint ignore:end */
}
// report to console if callback is not a valid function
if (callback && typeof callback != "function") {
console.warn("Invalid callback provided.");
return ()=>{}; //return noop function
}
return callback as Function;
};
//standardize voldata/volscheme in style
export function adjustVolumeStyle(style: IsoSurfaceSpec) {
if (style) {
if (style.volformat && !(style.voldata instanceof VolumeData)) {
style.voldata = new VolumeData(style.voldata, style.volformat);
}
if (style.volscheme) {
style.volscheme = Gradient.getGradient(style.volscheme);
}
}
};
/*
* computes the bounding box around the provided atoms
* @param {AtomSpec[]} atomlist
* @return {Array}
*/
export function getExtent(atomlist, ignoreSymmetries?) {
var xmin, ymin, zmin, xmax, ymax, zmax, xsum, ysum, zsum, cnt;
var includeSym = !ignoreSymmetries;
xmin = ymin = zmin = 9999;
xmax = ymax = zmax = -9999;
xsum = ysum = zsum = cnt = 0;
if (atomlist.length === 0)
return [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
for (var i = 0; i < atomlist.length; i++) {
var atom = atomlist[i];
if (typeof atom === 'undefined' || !isFinite(atom.x) ||
!isFinite(atom.y) || !isFinite(atom.z))
continue;
cnt++;
xsum += atom.x;
ysum += atom.y;
zsum += atom.z;
xmin = (xmin < atom.x) ? xmin : atom.x;
ymin = (ymin < atom.y) ? ymin : atom.y;
zmin = (zmin < atom.z) ? zmin : atom.z;
xmax = (xmax > atom.x) ? xmax : atom.x;
ymax = (ymax > atom.y) ? ymax : atom.y;
zmax = (zmax > atom.z) ? zmax : atom.z;
if (atom.symmetries && includeSym) {
for (var n = 0; n < atom.symmetries.length; n++) {
cnt++;
xsum += atom.symmetries[n].x;
ysum += atom.symmetries[n].y;
zsum += atom.symmetries[n].z;
xmin = (xmin < atom.symmetries[n].x) ? xmin : atom.symmetries[n].x;
ymin = (ymin < atom.symmetries[n].y) ? ymin : atom.symmetries[n].y;
zmin = (zmin < atom.symmetries[n].z) ? zmin : atom.symmetries[n].z;
xmax = (xmax > atom.symmetries[n].x) ? xmax : atom.symmetries[n].x;
ymax = (ymax > atom.symmetries[n].y) ? ymax : atom.symmetries[n].y;
zmax = (zmax > atom.symmetries[n].z) ? zmax : atom.symmetries[n].z;
}
}
}
return [[xmin, ymin, zmin], [xmax, ymax, zmax],
[xsum / cnt, ysum / cnt, zsum / cnt]];
};
/* get the min and max values of the specified property in the provided
* @function $3Dmol.getPropertyRange
* @param {AtomSpec[]} atomlist - list of atoms to evaluate
* @param {string} prop - name of property
* @return {Array} - [min, max] values
*/
export function getPropertyRange(atomlist, prop) {
var min = Number.POSITIVE_INFINITY;
var max = Number.NEGATIVE_INFINITY;
for (var i = 0, n = atomlist.length; i < n; i++) {
var atom = atomlist[i];
var val = getAtomProperty(atom, prop);
if (val != null) {
if (val < min)
min = val;
if (val > max)
max = val;
}
}
if (!isFinite(min) && !isFinite(max))
min = max = 0;
else if (!isFinite(min))
min = max;
else if (!isFinite(max))
max = min;
return [min, max];
};
//adapted from https://stackoverflow.com/questions/3969475/javascript-pause-settimeout
export class PausableTimer {
ident: any;
total_time_run = 0;
start_time: number;
countdown: number;
fn: any;
arg: any;
constructor(fn, countdown, arg?) {
this.fn = fn;
this.arg = arg;
this.countdown = countdown;
this.start_time = new Date().getTime();
this.ident = setTimeout(fn, countdown, arg);
}
cancel() {
clearTimeout(this.ident);
}
pause() {
clearTimeout(this.ident);
this.total_time_run = new Date().getTime() - this.start_time;
}
resume() {
this.ident = setTimeout(this.fn, Math.max(0, this.countdown - this.total_time_run), this.arg);
}
};
/*
* Convert a base64 encoded string to a Uint8Array
* @param {string} base64 encoded string
*/
export function base64ToArray(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes;
};
//return the value of an atom property prop, or null if non existent
// looks first in properties, then in the atom itself
export function getAtomProperty(atom, prop) {
var val = null;
if (atom.properties &&
typeof (atom.properties[prop]) != "undefined") {
val = atom.properties[prop];
} else if (typeof (atom[prop]) != 'undefined') {
val = atom[prop];
}
return val;
};
//Miscellaneous functions and classes - to be incorporated into $3Dmol proper
/*
*
* @param {$3Dmol.Geometry} geometry
* @param {$3Dmol.Mesh} mesh
* @returns {undefined}
*/
export function mergeGeos(geometry, mesh) {
var meshGeo = mesh.geometry;
if (meshGeo === undefined)
return;
geometry.geometryGroups.push(meshGeo.geometryGroups[0]);
};
/*
* Parse a string that represents a style or atom selection and convert it
* into an object. The goal is to make it easier to write out these specifications
* without resorting to json. Objects cannot be defined recursively.
* ; - delineates fields of the object
* : - if the field has a value other than an empty object, it comes after a colon
* , - delineates key/value pairs of a value object
* If the value object consists of ONLY keys (no = present) the keys are
* converted to a list. Otherwise a object of key/value pairs is created with
* any missing values set to null
* = OR ~ - separates key/value pairs of a value object, if not provided value is null
* twiddle is supported since = has special meaning in URLs
* @param (String) str
* @returns {Object}
*/
export function specStringToObject(str) {
if (typeof (str) === "object") {
return str; //not string, assume was converted already
}
else if (typeof (str) === "undefined" || str == null) {
return str;
}
//if this is a json string, parse it directly
try {
let parsed = JSON.parse(str);
return parsed;
} catch (error) {
}
str = str.replace(/%7E/g, '~'); //copy/pasting urls sometimes does this
//convert things that look like numbers into numbers
var massage = function (val) {
if (isNumeric(val)) {
//hexadecimal does not parse as float
if (Math.floor(parseFloat(val)) == parseInt(val)) {
return parseFloat(val);
}
else if (val.indexOf('.') >= 0) {
return parseFloat(val); // ".7" for example, does not parseInt
}
else {
return parseInt(val);
}
}
//boolean conversions
else if (val === 'true') {
return true;
}
else if (val === 'false') {
return false;
}
return val;
};
var ret = {};
if (str === 'all') return ret;
var fields = str.split(';');
for (var i = 0; i < fields.length; i++) {
var fv = fields[i].split(':');
var f = fv[0];
var val = {};
var vstr = fv[1];
if (vstr) {
vstr = vstr.replace(/~/g, "=");
if (vstr.indexOf('=') !== -1) {
//has key=value pairs, must be object
var kvs = vstr.split(',');
for (var j = 0; j < kvs.length; j++) {
var kv = kvs[j].split('=', 2);
val[kv[0]] = massage(kv[1]);
}
}
else if (vstr.indexOf(',') !== -1) {
//has multiple values, must list
val = vstr.split(',');
}
else {
val = massage(vstr); //value itself
}
}
ret[f] = val;
}
return ret;
};
function checkStatus(response) {
if (!response.ok) {
throw new Error(`HTTP ${response.status} - ${response.statusText}`);
}
return response;
}
/**
* Fetch data from URL
*
* @param uri URL
* @param callback Function to call with data
*/
export function get(uri, callback?) {
var promise = fetch(uri).then(checkStatus).then((response) => response.text());
if (callback)
return promise.then(callback);
else
return promise;
}
/**
* Download binary data (e.g. a gzipped file) into an array buffer and provide
* arraybuffer to callback.
* @param {string} uri - location of data
* @param {Function} [callback] - Function to call with arraybuffer as argument.
* @param {string} [request] - type of request
* @param {string} [postdata] - data for POST request
* @return {Promise}
*/
export function getbin(uri, callback?, request?, postdata?) {
var promise;
if (request == "POST") {
promise = fetch(uri, { method: 'POST', body: postdata })
.then((response) => checkStatus(response))
.then((response) => response.arrayBuffer());
} else {
promise = fetch(uri).then((response) => checkStatus(response))
.then((response) => response.arrayBuffer());
}
if (callback) return promise.then(callback);
else return promise;
};
/**
* Load a PDB/PubChem structure into existing viewer. Automatically calls 'zoomTo' and 'render' on viewer after loading model
* @param {string} query - String specifying pdb or pubchem id; must be prefaced with "pdb: " or "cid: ", respectively
* @param {GLViewer} viewer - Add new model to existing viewer
* @param {Object} options - Specify additional options
* format: file format to download, if multiple are available, default format is pdb
* pdbUri: URI to retrieve PDB files, default URI is http://www.rcsb.org/pdb/files/
* @param {Function} [callback] - Function to call with model as argument after data is loaded.
* @return {GLModel} GLModel, Promise if callback is not provided
* @example
viewer.setBackgroundColor(0xffffffff);
$3Dmol.download('pdb:2nbd',viewer,{onemol: true,multimodel: true},function(m) {
m.setStyle({'cartoon':{colorscheme:{prop:'ss',map:$3Dmol.ssColors.Jmol}}});
viewer.zoomTo();
viewer.render(callback);
});
*/
export function download(query, viewer: GLViewer, options, callback?) {
var type = "";
var pdbUri = "";
var uri = "";
var promise = null;
var m = viewer.addModel();
if (query.indexOf(':') < 0) {
//no type specifier, guess
if (query.length == 4) {
query = 'pdb:' + query;
} else if (!isNaN(query)) {
query = 'cid:' + query;
} else {
query = 'url:' + query;
}
}
if (query.substring(0,5) == 'mmtf:') {
console.warn('WARNING: MMTF now deprecated. Reverting to bcif.');
query = 'bcif:' + query.slice(5);
}
if (query.substring(0, 5) === 'bcif:') {
query = query.substring(5).toUpperCase();
uri = "https://models.rcsb.org/" + query + '.bcif.gz';
if (options && typeof options.noComputeSecondaryStructure === 'undefined') {
//when fetch directly from pdb, trust structure annotations
options.noComputeSecondaryStructure = true;
}
promise = new Promise(function (resolve) {
getbin(uri)
.then(function (ret) {
m.addMolData(ret, 'bcif.gz', options);
viewer.zoomTo();
viewer.render();
resolve(m);
}, function () { console.error("fetch of " + uri + " failed."); });
});
}
else {
if (query.substring(0, 4) === 'pdb:') {
type = 'bcif';
if (options && options.format) {
type = options.format; //can override and require pdb
}
if (options && typeof options.noComputeSecondaryStructure === 'undefined') {
//when fetch directly from pdb, trust structure annotations
options.noComputeSecondaryStructure = true;
}
query = query.substring(4).toUpperCase();
if (!query.match(/^[1-9][A-Za-z0-9]{3}$/)) {
alert("Wrong PDB ID");
return;
}
if (type == 'bcif') {
uri = 'https://models.rcsb.org/' + query.toUpperCase() + '.bcif.gz';
}
else {
pdbUri = options && options.pdbUri ? options.pdbUri : "https://files.rcsb.org/view/";
uri = pdbUri + query + "." + type;
}
} else if (query.substring(0, 4) == 'cid:') {
type = "sdf";
query = query.substring(4);
if (!query.match(/^[0-9]+$/)) {
alert("Wrong Compound ID"); return;
}
uri = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/" + query +
"/SDF?record_type=3d";
} else if (query.substring(0, 4) == 'url:') {
uri = query.substring(4);
type = uri;
}
var handler = function (ret) {
m.addMolData(ret, type, options);
viewer.zoomTo();
viewer.render();
};
promise = new Promise(function (resolve) {
if (type == 'bcif') { //binary data
getbin(uri)
.then(function (ret) {
handler(ret);
resolve(m);
}).catch(function () {
//if mmtf server is being annoying, fallback to text
pdbUri = options && options.pdbUri ? options.pdbUri : "https://files.rcsb.org/view/";
uri = pdbUri + query + ".pdb";
type = "pdb";
console.warn("falling back to pdb format");
get(uri).then(function (data) {
handler(data);
resolve(m);
}).catch(function (e) {
handler("");
resolve(m);
console.error("fetch of " + uri + " failed: " + e.statusText);
});
}); //an error msg has already been printed
}
else {
get(uri).then(function (data) {
handler(data);
resolve(m);
}).catch(function (e) {
handler("");
resolve(m);
console.error("fetch of " + uri + " failed: " + e.statusText);
});
}
});
}
if (callback) {
promise.then(function (m) {
callback(m);
});
return m;
}
else return promise;
};
/** Return proper color for atom given style
* @param {AtomSpec} atom
* @param {AtomStyle} style
* @return {Color}
*/
export function getColorFromStyle(atom, style): Color {
let scheme = style.colorscheme;
if (typeof builtinColorSchemes[scheme] != "undefined") {
scheme = builtinColorSchemes[scheme];
} else if (typeof scheme == "string" && scheme.endsWith("Carbon")) {
//any color you want of carbon
let ccolor = scheme
.substring(0, scheme.lastIndexOf("Carbon"))
.toLowerCase();
if (typeof htmlColors[ccolor] != "undefined") {
let newscheme = { ...elementColors.defaultColors };
newscheme.C = htmlColors[ccolor];
builtinColorSchemes[scheme] = { prop: "elem", map: newscheme };
scheme = builtinColorSchemes[scheme];
}
}
let color = atom.color;
if (typeof style.color != "undefined" && style.color != "spectrum")
color = style.color;
if (typeof scheme != "undefined") {
let prop, val;
if (typeof elementColors[scheme] != "undefined") {
//name of builtin colorscheme
scheme = elementColors[scheme];
if (typeof scheme[atom[scheme.prop]] != "undefined") {
color = scheme.map[atom[scheme.prop]];
}
} else if (typeof scheme[atom[scheme.prop]] != "undefined") {
//actual color scheme provided
color = scheme.map[atom[scheme.prop]];
} else if (
typeof scheme.prop != "undefined" &&
typeof scheme.gradient != "undefined"
) {
//apply a property mapping
prop = scheme.prop;
var grad = scheme.gradient; //redefining scheme
if(!(grad instanceof GradientType)) {
grad = getGradient(scheme);
}
let range = grad.range() || [-1, 1]; //sensible default
val = getAtomProperty(atom, prop);
if (val != null) {
color = grad.valueToHex(val, range);
}
} else if (
typeof scheme.prop != "undefined" &&
typeof scheme.map != "undefined"
) {
//apply a discrete property mapping
prop = scheme.prop;
val = getAtomProperty(atom, prop);
if (typeof scheme.map[val] != "undefined") {
color = scheme.map[val];
}
} else if (typeof style.colorscheme[atom.elem] != "undefined") {
//actual color scheme provided
color = style.colorscheme[atom.elem];
} else {
console.warn("Could not interpret colorscheme " + scheme);
}
} else if (typeof style.colorfunc != "undefined") {
//this is a user provided function for turning an atom into a color
color = style.colorfunc(atom);
}
let C = CC.color(color);
return C;
};
//given a string selector, element, or jquery object, return the HTMLElement
export function getElement(element): HTMLElement | null {
let ret = element;
if (typeof (element) === "string") {
ret = document.querySelector("#" + element);
} else if (typeof element === 'object' && element.get) { //jquery
ret = element.get(0);
}
return ret;
}
export function inflateString(str: string | ArrayBuffer, tostring: Boolean = true): (string | ArrayBuffer) {
let data: Data;
if (typeof str === 'string') {
const encoder = new TextEncoder();
data = encoder.encode(str);
} else {
data = new Uint8Array(str);
}
const inflatedData = inflate(data, {
to: tostring ? 'string' : null
} as InflateFunctionOptions & { to: 'string' });
return inflatedData;
}
</code></pre></article></section><footer class="footer" id="PeOAagUepe"><div class="wrapper">3Dmol.js © 2019-2024 | <a href="https://pitt.edu/" target="_blank">University of Pittsburgh</a> | <a href="https://github.com/3dmol/3Dmol.js/blob/master/LICENSE" target="_blank">License</a></div></footer></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><a href="/" class="sidebar-title sidebar-title-anchor">3Dmol.js</a><div class="mobile-nav-links"><div class="navbar-item"><a id="" href="https://3dmol.org/doc/index.html" target="">Documentation</a></div><div class="navbar-item"><a id="" href="tutorial-home.html" target="">Tutorials</a></div><div class="navbar-item"><a id="" href="https://github.com/3dmol/3Dmol.js" target="_blank">GitHub</a></div></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="mei5HJjYKLn6aua5Z5PM5"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="$3Dmol.Label.html">Label</a></div><div class="sidebar-section-children"><a href="$3Dmol.StateManager.html">StateManager</a></div><div class="sidebar-section-children"><a href="$3Dmol.UI.html">UI</a></div><div class="sidebar-section-children"><a href="Color.html">Color</a></div><div class="sidebar-section-children"><a href="CustomLinear.html">CustomLinear</a></div><div class="sidebar-section-children"><a href="Cylinder.html">Cylinder</a></div><div class="sidebar-section-children"><a href="GLModel.html">GLModel</a></div><div class="sidebar-section-children"><a href="GLShape.html">GLShape</a></div><div class="sidebar-section-children"><a href="GLShape_GLShape.html">GLShape</a></div><div class="sidebar-section-children"><a href="GLViewer.html">GLViewer</a></div><div class="sidebar-section-children"><a href="GLVolumetricRender.html">GLVolumetricRender</a></div><div class="sidebar-section-children"><a href="Matrix3.html">Matrix3</a></div><div class="sidebar-section-children"><a href="Matrix4.html">Matrix4</a></div><div class="sidebar-section-children"><a href="Quaternion.html">Quaternion</a></div><div class="sidebar-section-children"><a href="ROYGB.html">ROYGB</a></div><div class="sidebar-section-children"><a href="RWB.html">RWB</a></div><div class="sidebar-section-children"><a href="Ray.html">Ray</a></div><div class="sidebar-section-children"><a href="Sinebow.html">Sinebow</a></div><div class="sidebar-section-children"><a href="Sphere.html">Sphere</a></div><div class="sidebar-section-children"><a href="Surface.html">Surface</a></div><div class="sidebar-section-children"><a href="Triangle.html">Triangle</a></div><div class="sidebar-section-children"><a href="Vector2.html">Vector2</a></div><div class="sidebar-section-children"><a href="Vector3.html">Vector3</a></div><div class="sidebar-section-children"><a href="VolumeData.html">VolumeData</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="kv4Yx5z0THf_b8XR4Gje1"><div>Namespaces</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="GLDraw.html">GLDraw</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="ykThSufQWJcKGT1kXzr-A"><div>Tutorials</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="tutorial-code.html">Using 3Dmol within your code</a></div><div class="sidebar-section-children"><a href="tutorial-embeddable.html">Embedding a 3Dmol Viewer</a></div><div class="sidebar-section-children"><a href="tutorial-home.html">3Dmol Tutorials - Home</a></div><div class="sidebar-section-children"><a href="tutorial-learning_environment.html">Active Learning with 3Dmol.js</a></div><div class="sidebar-section-children"><a href="tutorial-url.html">Viewing Molecules with the 3Dmol Server</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="XcP4RUEg6tp7YKHbBVi9E"><div>Interfaces</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="AmbientOcclusionStyle.html">AmbientOcclusionStyle</a></div><div class="sidebar-section-children"><a href="ArrowSpec.html">ArrowSpec</a></div><div class="sidebar-section-children"><a href="AtomSelectionSpec.html">AtomSelectionSpec</a></div><div class="sidebar-section-children"><a href="AtomSpec.html">AtomSpec</a></div><div class="sidebar-section-children"><a href="AtomStyleSpec.html">AtomStyleSpec</a></div><div class="sidebar-section-children"><a href="BondStyle.html">BondStyle</a></div><div class="sidebar-section-children"><a href="BoxSpec.html">BoxSpec</a></div><div class="sidebar-section-children"><a href="CartoonStyleSpec.html">CartoonStyleSpec</a></div><div class="sidebar-section-children"><a href="ClickSphereStyleSpec.html">ClickSphereStyleSpec</a></div><div class="sidebar-section-children"><a href="CrossStyleSpec.html">CrossStyleSpec</a></div><div class="sidebar-section-children"><a href="CurveSpec.html">CurveSpec</a></div><div class="sidebar-section-children"><a href="CustomShapeSpec.html">CustomShapeSpec</a></div><div class="sidebar-section-children"><a href="CylinderSpec.html">CylinderSpec</a></div><div class="sidebar-section-children"><a href="DashedBondSpec.html">DashedBondSpec</a></div><div class="sidebar-section-children"><a href="FogSpec.html">FogSpec</a></div><div class="sidebar-section-children"><a href="IsoSurfaceSpec.html">IsoSurfaceSpec</a></div><div class="sidebar-section-children"><a href="LabelSpec.html">LabelSpec</a></div><div class="sidebar-section-children"><a href="LineSpec.html">LineSpec</a></div><div class="sidebar-section-children"><a href="LineStyleSpec.html">LineStyleSpec</a></div><div class="sidebar-section-children"><a href="OutlineStyle.html">OutlineStyle</a></div><div class="sidebar-section-children"><a href="ParserOptionsSpec.html">ParserOptionsSpec</a></div><div class="sidebar-section-children"><a href="ShapeSpec.html">ShapeSpec</a></div><div class="sidebar-section-children"><a href="SphereSpec.html">SphereSpec</a></div><div class="sidebar-section-children"><a href="SphereStyleSpec.html">SphereStyleSpec</a></div><div class="sidebar-section-children"><a href="StickStyleSpec.html">StickStyleSpec</a></div><div class="sidebar-section-children"><a href="SurfaceStyleSpec.html">SurfaceStyleSpec</a></div><div class="sidebar-section-children"><a href="UnitCellStyleSpec.html">UnitCellStyleSpec</a></div><div class="sidebar-section-children"><a href="ViewStyle.html">ViewStyle</a></div><div class="sidebar-section-children"><a href="ViewerGridSpec.html">ViewerGridSpec</a></div><div class="sidebar-section-children"><a href="ViewerSpec.html">ViewerSpec</a></div><div class="sidebar-section-children"><a href="VolumetricRendererSpec.html">VolumetricRendererSpec</a></div><div class="sidebar-section-children"><a href="WithinSelectionSpec.html">WithinSelectionSpec</a></div><div class="sidebar-section-children"><a href="global.html#XYZ">XYZ</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="jmKnIXRJjdjZ366ci7cdd"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#BCIF">BCIF</a></div><div class="sidebar-section-children"><a href="global.html#CAP">CAP</a></div><div class="sidebar-section-children"><a href="global.html#CDJSON">CDJSON</a></div><div class="sidebar-section-children"><a href="global.html#CIF">CIF</a></div><div class="sidebar-section-children"><a href="global.html#CUBE">CUBE</a></div><div class="sidebar-section-children"><a href="global.html#ColorSpec">ColorSpec</a></div><div class="sidebar-section-children"><a href="global.html#ColorschemeSpec">ColorschemeSpec</a></div><div class="sidebar-section-children"><a href="global.html#GRO">GRO</a></div><div class="sidebar-section-children"><a href="global.html#GradientSpec">GradientSpec</a></div><div class="sidebar-section-children"><a href="global.html#MMTFparser">MMTFparser</a></div><div class="sidebar-section-children"><a href="global.html#MOL2">MOL2</a></div><div class="sidebar-section-children"><a href="global.html#OFFSETS">OFFSETS</a></div><div class="sidebar-section-children"><a href="global.html#PDB">PDB</a></div><div class="sidebar-section-children"><a href="global.html#PQR">PQR</a></div><div class="sidebar-section-children"><a href="global.html#PRMTOP">PRMTOP</a></div><div class="sidebar-section-children"><a href="global.html#SDF">SDF</a></div><div class="sidebar-section-children"><a href="global.html#SurfaceType">SurfaceType</a></div><div class="sidebar-section-children"><a href="global.html#VASP">VASP</a></div><div class="sidebar-section-children"><a href="global.html#XYZ">XYZ</a></div><div class="sidebar-section-children"><a href="global.html#assignPDBBonds">assignPDBBonds</a></div><div class="sidebar-section-children"><a href="global.html#builtinColorSchemes">builtinColorSchemes</a></div><div class="sidebar-section-children"><a href="global.html#builtinGradients">builtinGradients</a></div><div class="sidebar-section-children"><a href="global.html#conversionMatrix3">conversionMatrix3</a></div><div class="sidebar-section-children"><a href="global.html#createViewer">createViewer</a></div><div class="sidebar-section-children"><a href="global.html#createViewerGrid">createViewerGrid</a></div><div class="sidebar-section-children"><a href="global.html#decode">decode</a></div><div class="sidebar-section-children"><a href="global.html#dic">dic</a></div><div class="sidebar-section-children"><a href="global.html#download">download</a></div><div class="sidebar-section-children"><a href="global.html#elementColors">elementColors</a></div><div class="sidebar-section-children"><a href="global.html#get">get</a></div><div class="sidebar-section-children"><a href="global.html#getColorFromStyle">getColorFromStyle</a></div><div class="sidebar-section-children"><a href="global.html#getbin">getbin</a></div><div class="sidebar-section-children"><a href="global.html#parseV3000">parseV3000</a></div><div class="sidebar-section-children"><a href="global.html#setSyncSurface">setSyncSurface</a></div><div class="sidebar-section-children"><a href="global.html#ssColors">ssColors</a></div><div class="sidebar-section-children"><a href="global.html#syncSurface">syncSurface</a></div><div class="sidebar-section-children"><a href="global.html#viewers">viewers</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-ri