Procházet zdrojové kódy

package updates, structure controls helper

Alexander Rose před 5 roky
rodič
revize
3e7d23f936

+ 128 - 65
package-lock.json

@@ -107,9 +107,9 @@
             "dev": true
         },
         "@types/node": {
-            "version": "12.7.2",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz",
-            "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==",
+            "version": "12.7.5",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz",
+            "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==",
             "dev": true
         },
         "@types/node-fetch": {
@@ -1712,9 +1712,9 @@
             }
         },
         "cyclist": {
-            "version": "0.2.2",
-            "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
-            "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
+            "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
             "dev": true
         },
         "d": {
@@ -1859,9 +1859,9 @@
             "dev": true
         },
         "diff": {
-            "version": "3.5.0",
-            "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
-            "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
+            "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
             "dev": true
         },
         "diffie-hellman": {
@@ -1916,9 +1916,9 @@
             "dev": true
         },
         "elliptic": {
-            "version": "6.5.0",
-            "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz",
-            "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==",
+            "version": "6.5.1",
+            "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz",
+            "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==",
             "dev": true,
             "requires": {
                 "bn.js": "^4.4.0",
@@ -1987,17 +1987,21 @@
             }
         },
         "es-abstract": {
-            "version": "1.13.0",
-            "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz",
-            "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==",
+            "version": "1.14.2",
+            "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz",
+            "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==",
             "dev": true,
             "requires": {
                 "es-to-primitive": "^1.2.0",
                 "function-bind": "^1.1.1",
                 "has": "^1.0.3",
+                "has-symbols": "^1.0.0",
                 "is-callable": "^1.1.4",
                 "is-regex": "^1.0.4",
-                "object-keys": "^1.0.12"
+                "object-inspect": "^1.6.0",
+                "object-keys": "^1.1.1",
+                "string.prototype.trimleft": "^2.0.0",
+                "string.prototype.trimright": "^2.0.0"
             }
         },
         "es-to-primitive": {
@@ -3393,9 +3397,9 @@
             "dev": true
         },
         "graphql": {
-            "version": "14.4.2",
-            "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.4.2.tgz",
-            "integrity": "sha512-6uQadiRgnpnSS56hdZUSvFrVcQ6OF9y6wkxJfKquFtHlnl7+KSuWwSJsdwiK1vybm1HgcdbpGkCpvhvsVQ0UZQ==",
+            "version": "14.5.4",
+            "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.4.tgz",
+            "integrity": "sha512-dPLvHoxy5m9FrkqWczPPRnH0X80CyvRE6e7Fa5AWEqEAzg9LpxHvKh24po/482E6VWHigOkAmb4xCp6P9yT9gw==",
             "dev": true,
             "requires": {
                 "iterall": "^1.2.2"
@@ -4437,9 +4441,9 @@
             }
         },
         "molstar": {
-            "version": "0.2.6",
-            "resolved": "https://registry.npmjs.org/molstar/-/molstar-0.2.6.tgz",
-            "integrity": "sha512-vN4BP7h2Z9nFoO0akTnS8tVezZ3u+C6IW/qVyuQCr8R+ROTXR2guNhm7Wyh+Ol9jaWWSZXvcTIsJh52NqJT7nQ==",
+            "version": "0.2.10",
+            "resolved": "https://registry.npmjs.org/molstar/-/molstar-0.2.10.tgz",
+            "integrity": "sha512-e1eleyhk12GjvxtN76NFfTJHo7p+RwP3C3Er2e9itBSHVjDLRneC6uRWhJ1NjaHuBHhLe8AjXGv7rEt9F6lvog==",
             "dev": true,
             "requires": {
                 "@types/argparse": "^1.0.36",
@@ -4447,7 +4451,7 @@
                 "@types/compression": "1.0.1",
                 "@types/express": "^4.17.1",
                 "@types/jest": "^24.0.18",
-                "@types/node": "^12.7.2",
+                "@types/node": "^12.7.4",
                 "@types/node-fetch": "^2.5.0",
                 "@types/react": "^16.9.2",
                 "@types/react-dom": "^16.9.0",
@@ -4456,15 +4460,26 @@
                 "argparse": "^1.0.10",
                 "compression": "^1.7.4",
                 "express": "^4.17.1",
-                "graphql": "^14.4.2",
+                "graphql": "^14.5.4",
                 "immutable": "^3.8.2",
                 "node-fetch": "^2.6.0",
                 "react": "^16.9.0",
                 "react-dom": "^16.9.0",
-                "rxjs": "^6.5.2",
-                "swagger-ui-dist": "^3.23.5",
+                "rxjs": "^6.5.3",
+                "swagger-ui-dist": "^3.23.9",
                 "util.promisify": "^1.0.0",
                 "xhr2": "^0.2.0"
+            },
+            "dependencies": {
+                "rxjs": {
+                    "version": "6.5.3",
+                    "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz",
+                    "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==",
+                    "dev": true,
+                    "requires": {
+                        "tslib": "^1.9.0"
+                    }
+                }
             }
         },
         "move-concurrently": {
@@ -4811,6 +4826,12 @@
                 }
             }
         },
+        "object-inspect": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
+            "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==",
+            "dev": true
+        },
         "object-keys": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@@ -4984,12 +5005,12 @@
             "dev": true
         },
         "parallel-transform": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz",
-            "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=",
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
+            "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
             "dev": true,
             "requires": {
-                "cyclist": "~0.2.2",
+                "cyclist": "^1.0.1",
                 "inherits": "^2.0.3",
                 "readable-stream": "^2.1.5"
             }
@@ -6053,24 +6074,46 @@
             }
         },
         "sass-loader": {
-            "version": "7.3.1",
-            "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz",
-            "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==",
+            "version": "8.0.0",
+            "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.0.tgz",
+            "integrity": "sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w==",
             "dev": true,
             "requires": {
                 "clone-deep": "^4.0.1",
-                "loader-utils": "^1.0.1",
-                "neo-async": "^2.5.0",
-                "pify": "^4.0.1",
+                "loader-utils": "^1.2.3",
+                "neo-async": "^2.6.1",
+                "schema-utils": "^2.1.0",
                 "semver": "^6.3.0"
             },
             "dependencies": {
-                "pify": {
-                    "version": "4.0.1",
-                    "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
-                    "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+                "ajv": {
+                    "version": "6.10.2",
+                    "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+                    "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+                    "dev": true,
+                    "requires": {
+                        "fast-deep-equal": "^2.0.1",
+                        "fast-json-stable-stringify": "^2.0.0",
+                        "json-schema-traverse": "^0.4.1",
+                        "uri-js": "^4.2.2"
+                    }
+                },
+                "ajv-keywords": {
+                    "version": "3.4.1",
+                    "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz",
+                    "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==",
                     "dev": true
                 },
+                "schema-utils": {
+                    "version": "2.2.0",
+                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.2.0.tgz",
+                    "integrity": "sha512-5EwsCNhfFTZvUreQhx/4vVQpJ/lnCAkgoIHLhSpp4ZirE+4hzFvdJi0FMub6hxbFVBJYSpeVVmon+2e7uEGRrA==",
+                    "dev": true,
+                    "requires": {
+                        "ajv": "^6.10.2",
+                        "ajv-keywords": "^3.4.1"
+                    }
+                },
                 "semver": {
                     "version": "6.3.0",
                     "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -6157,9 +6200,9 @@
             }
         },
         "serialize-javascript": {
-            "version": "1.8.0",
-            "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.8.0.tgz",
-            "integrity": "sha512-3tHgtF4OzDmeKYj6V9nSyceRS0UJ3C7VqyD2Yj28vC/z2j6jG5FmFGahOKMD9CrglxTm3tETr87jEypaYV8DUg==",
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz",
+            "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==",
             "dev": true
         },
         "serve-static": {
@@ -6602,6 +6645,26 @@
                 "strip-ansi": "^4.0.0"
             }
         },
+        "string.prototype.trimleft": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz",
+            "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.3",
+                "function-bind": "^1.1.1"
+            }
+        },
+        "string.prototype.trimright": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz",
+            "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.3",
+                "function-bind": "^1.1.1"
+            }
+        },
         "string_decoder": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -6701,9 +6764,9 @@
             }
         },
         "swagger-ui-dist": {
-            "version": "3.23.5",
-            "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.23.5.tgz",
-            "integrity": "sha512-fsCF3wR0kBF5G7yF8uD5kALSbo2TjpfdheXWnrmxD2/d/8bgKDlUVoqO4gMNrZRQOEbyXCexZiU9geMNspWWyA==",
+            "version": "3.23.9",
+            "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.23.9.tgz",
+            "integrity": "sha512-YfE6T0ls96vZhziGlEwdlqRH5S5IrpLSG3XWYHRHtOQ8npd7xGEEOUJL3xOypvB4/iE6yvxodc4SALZ5nILqkw==",
             "dev": true
         },
         "tapable": {
@@ -6724,9 +6787,9 @@
             }
         },
         "terser": {
-            "version": "4.2.0",
-            "resolved": "https://registry.npmjs.org/terser/-/terser-4.2.0.tgz",
-            "integrity": "sha512-6lPt7lZdZ/13icQJp8XasFOwZjFJkxFFIb/N1fhYEQNoNI3Ilo3KABZ9OocZvZoB39r6SiIk/0+v/bt8nZoSeA==",
+            "version": "4.3.1",
+            "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.1.tgz",
+            "integrity": "sha512-pnzH6dnFEsR2aa2SJaKb1uSCl3QmIsJ8dEkj0Fky+2AwMMcC9doMqLOQIH6wVTEKaVfKVvLSk5qxPBEZT9mywg==",
             "dev": true,
             "requires": {
                 "commander": "^2.20.0",
@@ -6896,16 +6959,16 @@
             "dev": true
         },
         "tslint": {
-            "version": "5.19.0",
-            "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.19.0.tgz",
-            "integrity": "sha512-1LwwtBxfRJZnUvoS9c0uj8XQtAnyhWr9KlNvDIdB+oXyT+VpsOAaEhEgKi1HrZ8rq0ki/AAnbGSv4KM6/AfVZw==",
+            "version": "5.20.0",
+            "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz",
+            "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==",
             "dev": true,
             "requires": {
                 "@babel/code-frame": "^7.0.0",
                 "builtin-modules": "^1.1.1",
                 "chalk": "^2.3.0",
                 "commander": "^2.12.1",
-                "diff": "^3.2.0",
+                "diff": "^4.0.1",
                 "glob": "^7.1.1",
                 "js-yaml": "^3.13.1",
                 "minimatch": "^3.0.4",
@@ -6963,9 +7026,9 @@
             "dev": true
         },
         "typescript": {
-            "version": "3.5.3",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
-            "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
+            "version": "3.6.3",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
+            "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
             "dev": true
         },
         "union-value": {
@@ -7051,9 +7114,9 @@
             }
         },
         "upath": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz",
-            "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==",
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+            "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
             "dev": true
         },
         "uri-js": {
@@ -7183,9 +7246,9 @@
             }
         },
         "webpack": {
-            "version": "4.39.2",
-            "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.2.tgz",
-            "integrity": "sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==",
+            "version": "4.39.3",
+            "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.3.tgz",
+            "integrity": "sha512-BXSI9M211JyCVc3JxHWDpze85CvjC842EvpRsVTc/d15YJGlox7GIDd38kJgWrb3ZluyvIjgenbLDMBQPDcxYQ==",
             "dev": true,
             "requires": {
                 "@webassemblyjs/ast": "1.8.5",
@@ -7250,9 +7313,9 @@
             }
         },
         "webpack-cli": {
-            "version": "3.3.7",
-            "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.7.tgz",
-            "integrity": "sha512-OhTUCttAsr+IZSMVwGROGRHvT+QAs8H6/mHIl4SvhAwYywjiylYjpwybGx7WQ9Hkb45FhjtsymkwiRRbGJ1SZQ==",
+            "version": "3.3.8",
+            "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.8.tgz",
+            "integrity": "sha512-RANYSXwikSWINjHMd/mtesblNSpjpDLoYTBtP99n1RhXqVI/wxN40Auqy42I7y4xrbmRBoA5Zy5E0JSBD5XRhw==",
             "dev": true,
             "requires": {
                 "chalk": "2.4.2",

+ 8 - 7
package.json

@@ -21,6 +21,7 @@
         "watch-tsc": "tsc -watch",
         "watch-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html}\" build/src/ --watch",
         "watch-webpack": "webpack -w --mode development --display minimal",
+        "serve": "http-server -p 1335",
         "preversion": "npm run test",
         "postversion": "git push && git push --tags",
         "prepublishOnly": "npm run test && npm run build"
@@ -29,7 +30,7 @@
     "license": "MIT",
     "devDependencies": {
         "@types/argparse": "^1.0.36",
-        "@types/node": "^12.7.2",
+        "@types/node": "^12.7.5",
         "@types/node-fetch": "^2.5.0",
         "@types/react": "^16.9.2",
         "@types/react-dom": "^16.9.0",
@@ -38,20 +39,20 @@
         "css-loader": "^3.2.0",
         "extra-watch-webpack-plugin": "^1.0.3",
         "file-loader": "^4.2.0",
-        "molstar": "^0.2.6",
         "mini-css-extract-plugin": "^0.8.0",
+        "molstar": "^0.2.10",
         "node-fetch": "^2.6.0",
         "node-sass": "^4.12.0",
         "raw-loader": "^3.1.0",
         "react": "^16.9.0",
         "react-dom": "^16.9.0",
         "resolve-url-loader": "^3.1.0",
-        "sass-loader": "^7.3.1",
+        "sass-loader": "^8.0.0",
         "style-loader": "^1.0.0",
-        "tslint": "^5.19.0",
-        "typescript": "3.5.3",
-        "webpack": "^4.39.2",
-        "webpack-cli": "^3.3.7"
+        "tslint": "^5.20.0",
+        "typescript": "3.6.3",
+        "webpack": "^4.39.3",
+        "webpack-cli": "^3.3.8"
     },
     "dependencies": {}
 }

+ 9 - 1
src/structure-viewer/helpers.ts

@@ -2,13 +2,21 @@
  * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
- * @author David Sehnal <david.sehnal@gmail.com>
  */
 
 export type SupportedFormats = 'cif' | 'pdb'
 export interface LoadParams {
+    /** URL pointing to a structure file  */
     url: string,
+    /** A supported file format extension string */
     format?: SupportedFormats,
+    /**
+     * The assemblyId to show initially
+     * - 'deposited' for the structure as it is given in the file
+     * - a number as string, e.g. '1', '2', ... must be defined in the file
+     * - 'unitcell' for the unitcell of an X-ray structure
+     * - 'supercell' for the supercell of an X-ray structure
+     */
     assemblyId?: string,
 }
 

+ 129 - 9
src/structure-viewer/index.html

@@ -17,6 +17,16 @@
                 width: 1024px;
                 height: 800px;
             }
+
+            #menu {
+                position: absolute;
+                right: 100px;
+                top: 100px;
+            }
+
+            #menu > select {
+                width: 200px;
+            }
         </style>
         <link rel="stylesheet" type="text/css" href="app.css" />
         <script type="text/javascript" src="./app.js"></script>
@@ -30,18 +40,128 @@
                 return m ? decodeURIComponent(m[1]) : undefined
             }
 
+            function getLoadParams(pdbId) {
+                return {
+                    assemblyId: getQueryParam('assemblyId') || 'deposited',
+                    url: 'https://files.rcsb.org/download/' + pdbId + '.cif',
+                    format: 'cif'
+                }
+            }
+
             // create an instance of the plugin
             var viewer = new app.StructureViewer();
-
-            function $(id) { return document.getElementById(id); }
-
-            var pdbId = getQueryParam('pdbId') || '3pqr'
-            var assemblyId = getQueryParam('assemblyId') || 'deposited';
-            var url = 'https://files.rcsb.org/download/' + pdbId + '.cif';
-            var format = 'cif';
-
             viewer.init('app', { });
-            viewer.load({ url: url, format: format, assemblyId: assemblyId });
+            const pdbId = getQueryParam('pdbId');
+            if (pdbId) viewer.load(getLoadParams(pdbId));
+        </script>
+        <div id="menu">
+            Examples
+            <select id="examples" onchange="viewer.load(getLoadParams(this.value))">
+                <option value=''></option>
+            </select>
+        </div>
+        <script>
+            var examples = [
+                {
+                    id: '1CRN',
+                    info: 'small: only polymer'
+                },
+                {
+                    id: '3PQR',
+                    info: 'medium: polymer, carbs, ligands'
+                },
+                {
+                    id: '6QVK',
+                    info: 'large: The cryo-EM structure of bacteriophage phi29 prohead'
+                },
+                {
+                    id: '5Y6P',
+                    info: 'large: Structure of the phycobilisome from the red alga Griffithsia pacifica'
+                },
+                {
+                    id: '6O2S',
+                    info: 'large: Deacetylated Microtubules'
+                },
+                {
+                    id: '5MQ7',
+                    info: 'large: Structure of AaLS-13'
+                },
+                {
+                    id: '5IV5',
+                    info: 'large: Cryo-electron microscopy structure of the hexagonal pre-attachment T4 baseplate-tail tube complex'
+                },
+                {
+                    id: '3JC8',
+                    info: 'large: Architectural model of the type IVa pilus machine in a piliated state'
+                },
+                {
+                    id: '4V99',
+                    info: 'large: The Crystallographic Structure of Panicum Mosaic Virus'
+                },
+                {
+                    id: '3J3Q',
+                    info: 'large: Atomic-level structure of the entire HIV-1 capsid'
+                },
+                {
+                    id: '6NCL',
+                    info: 'large: Near-atomic structure of icosahedrally averaged PBCV-1 capsid'
+                },
+                {
+                    id: '6EKC',
+                    info: 'large: Crystal structure of the BSD2 homolog of Arabidopsis thaliana bound to the octameric assembly of RbcL from Thermosynechococcus elongatus'
+                },
+                {
+                    id: '1M4X',
+                    info: 'large: PBCV-1 virus capsid, quasi-atomic model'
+                },
+                {
+                    id: '4V5A',
+                    info: 'large: Structure of the Ribosome Recycling Factor bound to the Thermus thermophilus 70S ribosome with mRNA, ASL-Phe and tRNA-fMet'
+                },
+                {
+                    id: '4UDF',
+                    info: 'large: STRUCTURAL BASIS OF HUMAN PARECHOVIRUS NEUTRALIZATION BY HUMAN MONOCLONAL ANTIBODIES'
+                },
+                {
+                    id: '6J5K',
+                    info: 'Cryo-EM structure of the mammalian ATP synthase tetramer bound with inhibitory protein IF1'
+                },
+                {
+                    id: '6RVV',
+                    info: 'Structure of left-handed protein cage consisting of 24 eleven-membered ring proteins held together by gold (I) bridges.'
+                },
+                {
+                    id: '6EK5',
+                    info: 'Near-atomic resolution structure of a plant geminivirus determined by electron cryo-microscopy'
+                },
+                {
+                    id: '4V93',
+                    info: 'Fitted coordinates for Lumbricus terrestris hemoglobin cryo-EM complex'
+                },
+                {
+                    id: '5VLZ',
+                    info: 'Backbone model for phage Qbeta capsid'
+                },
+                {
+                    id: '5XTI',
+                    info: 'Cryo-EM architecture of human respiratory chain megacomplex-I2III2IV2'
+                },
+                {
+                    id: '6BY7',
+                    info: 'Folding DNA into a lipid-conjugated nano-barrel for controlled reconstitution of membrane proteins'
+                },
+                {
+                    id: '6C50',
+                    info: 'Cross-alpha Amyloid-like Structure alphaAmS'
+                }
+            ];
+
+            var examplesSelect = document.getElementById('examples');
+            examples.forEach(function(e) {
+                var option = document.createElement('option')
+                Object.assign(option, { text: '[' + e.id + '] ' + e.info, value: e.id })
+                examplesSelect.appendChild(option)
+            })
         </script>
     </body>
 </html>

+ 28 - 38
src/structure-viewer/index.ts

@@ -2,7 +2,6 @@
  * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
- * @author David Sehnal <david.sehnal@gmail.com>
  */
 
 import { createPlugin, DefaultPluginSpec } from 'molstar/lib/mol-plugin';
@@ -23,14 +22,13 @@ import { PluginSpec } from 'molstar/lib/mol-plugin/spec';
 import { StructureRepresentationInteraction } from 'molstar/lib/mol-plugin/behavior/dynamic/selection/structure-representation-interaction';
 import { Model } from 'molstar/lib/mol-model/structure';
 import { ColorNames } from 'molstar/lib/mol-util/color/names';
+import { StructureControlsHelper } from './ui/structure';
 require('./skin/rcsb.scss')
 
 export class StructureViewer {
     plugin: PluginContext;
 
-    init(target: string | HTMLElement, options?: {
-        // TODO
-    }) {
+    init(target: string | HTMLElement) {
         target = typeof target === 'string' ? document.getElementById(target)! : target
         this.plugin = createPlugin(target, {
             ...DefaultPluginSpec,
@@ -38,8 +36,13 @@ export class StructureViewer {
                 PluginSpec.Behavior(PluginBehaviors.Representation.HighlightLoci),
                 PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci),
                 PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
-                PluginSpec.Behavior(PluginBehaviors.Camera.FocusLociOnSelect, { minRadius: 8, extraRadius: 4 }),
-                PluginSpec.Behavior(PluginBehaviors.CustomProps.RCSBAssemblySymmetry, { autoAttach: true }),
+                PluginSpec.Behavior(PluginBehaviors.Camera.FocusLociOnSelect, {
+                    minRadius: 8,
+                    extraRadius: 4
+                }),
+                PluginSpec.Behavior(PluginBehaviors.CustomProps.RCSBAssemblySymmetry, {
+                    autoAttach: true
+                }),
                 PluginSpec.Behavior(StructureRepresentationInteraction)
             ],
             animations: [
@@ -81,51 +84,37 @@ export class StructureViewer {
             .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 }, { ref: StateElements.Model });
     }
 
-    private structure(assemblyId: string) {
-        const model = this.state.build().to(StateElements.Model);
+    // private structure(assemblyId: string) {
+    //     const model = this.state.build().to(StateElements.Model);
 
-        const s = model
-            .apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: StateElements.Assembly });
+    //     const s = model
+    //         .apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: StateElements.Assembly });
 
-        return s;
-    }
+    //     return s;
+    // }
 
     private applyState(tree: StateBuilder) {
         return PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
     }
 
-    private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
     async load({ url, format = 'cif', assemblyId = '' }: LoadParams) {
-        let loadType: 'full' | 'update' = 'full';
+        if (!url) return
 
         const state = this.plugin.state.dataState;
+        await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
 
-        if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
-            loadType = 'full';
-        } else if (this.loadedParams.url === url) {
-            if (state.select(StateElements.Assembly).length > 0) loadType = 'update';
-        }
+        const modelTree = this.model(this.download(state.build().toRoot(), url), format);
+        await this.applyState(modelTree);
 
-        if (loadType === 'full') {
-            await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
-            const modelTree = this.model(this.download(state.build().toRoot(), url), format);
-            await this.applyState(modelTree);
-            const structureTree = this.structure(assemblyId);
-            await this.applyState(structureTree);
-        } else {
-            const tree = state.build();
-            tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
-            await this.applyState(tree);
-        }
+        await this.structureControlsHelper.setAssembly(assemblyId)
 
-        await this.plugin.helpers.structureRepresentation.preset();
-
-        this.loadedParams = { url, format, assemblyId };
         Scheduler.setImmediate(() => PluginCommands.Camera.Reset.dispatch(this.plugin, { }));
 
         this.experimentalData.init()
     }
 
+    structureControlsHelper = new StructureControlsHelper(this.plugin)
+
     experimentalData = {
         init: async () => {
             const model = this.state.select(StateElements.Model)[0].obj;
@@ -133,10 +122,11 @@ export class StructureViewer {
             if (!model || !asm) return
 
             const m = model.data as Model
-            const hasXrayMap = m.sourceData.data.pdbx_database_status.status_code_sf.value(0) === 'REL'
+            const d = m.sourceData.data
+            const hasXrayMap = d.pdbx_database_status.status_code_sf.value(0) === 'REL'
             let hasEmMap = false
-            for (let i = 0, il = m.sourceData.data.pdbx_database_related._rowCount; i < il; ++i) {
-                if (m.sourceData.data.pdbx_database_related.db_name.value(i).toUpperCase() === 'EMDB') {
+            for (let i = 0, il = d.pdbx_database_related._rowCount; i < il; ++i) {
+                if (d.pdbx_database_related.db_name.value(i).toUpperCase() === 'EMDB') {
                     hasEmMap = true
                     break
                 }
@@ -149,10 +139,10 @@ export class StructureViewer {
                 await this.plugin.runTask(this.state.applyAction(InitVolumeStreaming, params, StateElements.Assembly));
             }
         },
-        remove: () => {
+        remove: async () => {
             const r = this.state.select(StateSelection.Generators.ofTransformer(CreateVolumeStreamingInfo))[0];
             if (!r) return;
-            PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.state, ref: r.transform.ref });
+            await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.state, ref: r.transform.ref });
         }
     }
 }

+ 25 - 15
src/structure-viewer/ui/structure.tsx

@@ -15,6 +15,7 @@ import { PluginStateObject as PSO } from 'molstar/lib/mol-plugin/state/objects';
 import { StateTransforms } from 'molstar/lib/mol-plugin/state/transforms';
 import { Vec3 } from 'molstar/lib/mol-math/linear-algebra';
 import { Model } from 'molstar/lib/mol-model/structure';
+import { PluginContext } from 'molstar/lib/mol-plugin/context';
 
 type StructureControlsState = {
     isCollapsed: boolean
@@ -24,8 +25,8 @@ type StructureControlsProps = {
 
 }
 
-export class StructureControls<P extends StructureControlsProps, S extends StructureControlsState> extends PluginUIComponent<P, S> {
-    private applyState(tree: StateBuilder) {
+export class StructureControlsHelper {
+    applyState(tree: StateBuilder) {
         return PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
     }
 
@@ -36,14 +37,14 @@ export class StructureControls<P extends StructureControlsProps, S extends Struc
     async setAssembly(id: string) {
         const state = this.plugin.state.dataState;
         const tree = state.build();
-        if (id === '__unitcell__') {
+        if (id === 'unitcell') {
             const props = { ijkMin: Vec3.create(0, 0, 0), ijkMax: Vec3.create(0, 0, 0) }
             tree.delete(StateElements.Assembly)
                 .to(StateElements.Model).apply(
                     StateTransforms.Model.StructureSymmetryFromModel,
                     props, { ref: StateElements.Assembly, tags: [ 'unitcell' ] }
                 )
-        } else if (id === '__supercell__') {
+        } else if (id === 'supercell') {
             const props = { ijkMin: Vec3.create(-1, -1, -1), ijkMax: Vec3.create(1, 1, 1) }
             tree.delete(StateElements.Assembly)
                 .to(StateElements.Model).apply(
@@ -56,10 +57,6 @@ export class StructureControls<P extends StructureControlsProps, S extends Struc
                     StateTransforms.Model.StructureAssemblyFromModel,
                     { id }, { ref: StateElements.Assembly }
                 )
-            // tree.to(StateElements.Assembly).update(
-            //     StateTransforms.Model.StructureAssemblyFromModel,
-            //     props => ({ ...props, id: p.value })
-            // );
         }
         await this.applyState(tree)
         await this.preset()
@@ -99,6 +96,19 @@ export class StructureControls<P extends StructureControlsProps, S extends Struc
         }
     }
 
+    constructor(private plugin: PluginContext) {
+
+    }
+}
+
+export class StructureControls<P extends StructureControlsProps, S extends StructureControlsState> extends PluginUIComponent<P, S> {
+    structureControlsHelper: StructureControlsHelper
+
+    constructor(props: P, context?: any) {
+        super(props, context);
+        this.structureControlsHelper = new StructureControlsHelper(this.plugin)
+    }
+
     async setColorTheme(theme: { [k: string]: string }) {
         const { themeCtx } = this.plugin.structureRepresentation
         const state = this.plugin.state.dataState;
@@ -117,15 +127,15 @@ export class StructureControls<P extends StructureControlsProps, S extends Struc
                 )
             }
         })
-        await this.applyState(tree)
+        await this.structureControlsHelper.applyState(tree)
     }
 
     onChange = async (p: { param: PD.Base<any>, name: string, value: any }) => {
         console.log('onChange', p.name, p.value)
         if (p.name === 'assembly') {
-            this.setAssembly(p.value)
+            this.structureControlsHelper.setAssembly(p.value)
         } else if (p.name === 'model') {
-            this.setModel(p.value)
+            this.structureControlsHelper.setModel(p.value)
         } else if (p.name === 'colorThemes') {
             this.setColorTheme(p.value)
         }
@@ -150,7 +160,7 @@ export class StructureControls<P extends StructureControlsProps, S extends Struc
                 modelOptions.push([i, `${i + 1}`])
             }
             if (trajectory.data.length === 1 && modelHasSymmetry(trajectory.data[0])) {
-                assemblyOptions.push(['__unitcell__', 'unitcell'], ['__supercell__', 'supercell'])
+                assemblyOptions.push(['unitcell', 'unitcell'], ['supercell', 'supercell'])
             }
         }
 
@@ -220,9 +230,9 @@ export class StructureControls<P extends StructureControlsProps, S extends Struc
         if (assembly) {
             const tags = (assembly as StateObject).tags
             if (tags && tags.includes('unitcell')) {
-                assemblyValue = '__unitcell__'
+                assemblyValue = 'unitcell'
             } else if (tags && tags.includes('supercell')) {
-                assemblyValue = '__supercell__'
+                assemblyValue = 'supercell'
             } else {
                 assemblyValue = assembly.data.units[0].conformation.operator.assembly.id || 'deposited'
             }
@@ -297,7 +307,7 @@ export class StructureControls<P extends StructureControlsProps, S extends Struc
     }
 
     private getAssembly() {
-        if (!this.state.trajectoryRef) return
+        if (!this.state.trajectoryRef || !this.plugin.state.dataState.transforms.has(this.state.trajectoryRef)) return
         const assemblies = this.plugin.state.dataState.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure, this.state.trajectoryRef))
         return assemblies.length > 0 ? assemblies[0].obj : undefined
     }

+ 0 - 1
webpack.config.js

@@ -31,7 +31,6 @@ const sharedConfig = {
         }),
         new webpack.DefinePlugin({
             __PLUGIN_VERSION_TIMESTAMP__: webpack.DefinePlugin.runtimeValue(() => `${new Date().valueOf()}`, true),
-            'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
             'process.env.DEBUG': JSON.stringify(process.env.DEBUG)
         }),
         new MiniCssExtractPlugin({ filename: 'app.css' })