mirror of
https://github.com/molstar/molstar.git
synced 2026-06-05 14:04:36 +08:00
Compare commits
9 Commits
v5.0.0-dev
...
v5.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33dc2015df | ||
|
|
fcf5ea420b | ||
|
|
8d97327f8d | ||
|
|
abc7ebba3e | ||
|
|
73d593907e | ||
|
|
0dc05e1138 | ||
|
|
dd11cacae4 | ||
|
|
b503259758 | ||
|
|
1e98741e16 |
@@ -19,8 +19,9 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
- MolViewSpec extension:
|
||||
- Generic color schemes (`palette` parameter for color_from_* nodes)
|
||||
- Annotation field remapping (`field_remapping` parameter for color_from_* nodes)
|
||||
- Representation node: support custom property `molstar_reprepresentation_params`,
|
||||
- Canvas node: support custom properties `molstar_enable_outline`, `molstar_enable_shadow`, `molstar_enable_ssao`
|
||||
- Representation node: support custom property `molstar_reprepresentation_params`
|
||||
- Primitives node: support custom property `molstar_mesh/label/line_params`
|
||||
- Canvas node: support custom property `molstar_postprocessing` with the ability to customize outline, depth of field, bloom, shadow, occlusion (SSAO), and fog
|
||||
- `clip` node support for structure and volume representations
|
||||
- `grid_slice` representation support for volumes
|
||||
- Support tethers and background for primitive labels
|
||||
|
||||
@@ -14,12 +14,20 @@ The main use case of this is enriching [MolViewSpec](`https://molstar.org/mol-vi
|
||||
|
||||
Extends Markdown Hyperlink syntax to support expressions of the form `[title](!c1=v1&c2=v2&...)` into an executable command. The command can be executed either on click, mouse enter, or mouse leave.
|
||||
|
||||
Generally, the command should be URL encoded, e.g., `a b` => `a%20b` (in JS, `encodeURIComponent`, in Python `urllib.parse.quote_plus/urlencode`).
|
||||
|
||||
### Built-in Commands
|
||||
|
||||
- `center-camera` - Centers the camera
|
||||
- `apply-snapshot=key` - Loads snapshots with the provided key
|
||||
- `focus-refs=ref1,ref2,...` - On click, focuses nodes with the provided refs
|
||||
- `highlight-refs=ref1,ref2,...` - On mouse over, highlights the provided refs
|
||||
- `query=...&lang=...&action=highlight,focus&focus-radius=...`
|
||||
- `query` is an expression (e.g., `resn HEM` when using PyMol syntax)
|
||||
- (optional) `lang` is one of `mol-script` (default), `pymol`, `vmd`, `jmol`
|
||||
- (optional) `action` is an array of `highlight` (default), `focus` (multiple actions can be specified)
|
||||
- (optional) `focus-radius` is extra distance applied when focusing the selection (default is `3`)
|
||||
- Example: `[HEM](!query%3Dresn%20HEM%26lang%3Dpymol%26action%3Dhighlight%2Cfocus)` highlights or focuses the HEM residue (the command must be URL encoded because it contains spaces and possibly other special characters)
|
||||
|
||||
## Custom Content
|
||||
|
||||
@@ -28,7 +36,7 @@ Extends Markdown Image syntax to support expressions of the form `
|
||||
- `color-palette-name=name` - Renders a gradient with the provided named color palette (see `mol-util/color/lists.ts` for supported color schemes)
|
||||
- `color-palette-colors=color1,color2` - Renders a gradient with the provided colors
|
||||
- `color-palette-width=CCS-value` - Specifies the width of the element, defaults to `150px`
|
||||
- `color-palette-height=CCS-value` - Specified the height of the element, defaults to `0.5em`
|
||||
|
||||
54
package-lock.json
generated
54
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "5.0.0-dev.2",
|
||||
"version": "5.0.0-dev.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "molstar",
|
||||
"version": "5.0.0-dev.2",
|
||||
"version": "5.0.0-dev.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/argparse": "^2.0.17",
|
||||
@@ -1171,9 +1171,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz",
|
||||
"integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==",
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz",
|
||||
"integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -2763,7 +2763,7 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -3021,7 +3021,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"devOptional": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/basic-auth": {
|
||||
"version": "2.0.1",
|
||||
@@ -3081,7 +3081,7 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
@@ -3494,7 +3494,7 @@
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"devOptional": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "9.1.2",
|
||||
@@ -4127,7 +4127,7 @@
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"devOptional": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "2.0.0",
|
||||
@@ -5012,7 +5012,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"devOptional": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
@@ -5170,7 +5170,7 @@
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
@@ -5203,7 +5203,7 @@
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
@@ -5214,7 +5214,7 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@@ -5297,7 +5297,7 @@
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"devOptional": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/graphemer": {
|
||||
"version": "1.4.0",
|
||||
@@ -5621,7 +5621,7 @@
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.19"
|
||||
}
|
||||
@@ -5630,7 +5630,7 @@
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
@@ -5838,7 +5838,7 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -6080,7 +6080,7 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"devOptional": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/istanbul-lib-coverage": {
|
||||
"version": "3.2.2",
|
||||
@@ -7980,7 +7980,7 @@
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -8357,7 +8357,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -9162,7 +9162,7 @@
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"devOptional": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/safe-identifier": {
|
||||
"version": "0.4.2",
|
||||
@@ -9518,7 +9518,7 @@
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"devOptional": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/simple-git": {
|
||||
"version": "3.28.0",
|
||||
@@ -9639,7 +9639,7 @@
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
@@ -9721,7 +9721,7 @@
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
@@ -10454,7 +10454,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"devOptional": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/util.promisify": {
|
||||
"version": "1.1.3",
|
||||
@@ -10577,7 +10577,7 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "5.0.0-dev.2",
|
||||
"version": "5.0.0-dev.4",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
*/
|
||||
|
||||
import { Camera } from '../../mol-canvas3d/camera';
|
||||
import { Canvas3DParams, Canvas3DProps } from '../../mol-canvas3d/canvas3d';
|
||||
import { CameraFogParams, Canvas3DParams, Canvas3DProps } from '../../mol-canvas3d/canvas3d';
|
||||
import { BloomParams } from '../../mol-canvas3d/passes/bloom';
|
||||
import { DofParams } from '../../mol-canvas3d/passes/dof';
|
||||
import { OutlineParams } from '../../mol-canvas3d/passes/outline';
|
||||
import { ShadowParams } from '../../mol-canvas3d/passes/shadow';
|
||||
import { SsaoParams } from '../../mol-canvas3d/passes/ssao';
|
||||
@@ -129,24 +131,49 @@ export function modifyCanvasProps(oldCanvasProps: Canvas3DProps, canvasNode: Mol
|
||||
const params = canvasNode?.params;
|
||||
const backgroundColor = decodeColor(params?.background_color) ?? DefaultCanvasBackgroundColor;
|
||||
|
||||
const outline = !!canvasNode?.custom?.molstar_enable_outline;
|
||||
const shadow = !!canvasNode?.custom?.molstar_enable_shadow;
|
||||
const occlusion = !!canvasNode?.custom?.molstar_enable_ssao;
|
||||
const molstar_postprocessing = canvasNode?.custom?.molstar_postprocessing;
|
||||
|
||||
const outline = !!molstar_postprocessing?.enable_outline;
|
||||
const outlineParams = molstar_postprocessing?.outline_params;
|
||||
|
||||
const shadow = !!molstar_postprocessing?.enable_shadow;
|
||||
const shadowParams = molstar_postprocessing?.shadow_params;
|
||||
|
||||
const occlusion = !!molstar_postprocessing?.enable_ssao;
|
||||
const occlusionParams = molstar_postprocessing?.ssao_params;
|
||||
|
||||
const fog = !!molstar_postprocessing?.enable_fog;
|
||||
const fogParams = molstar_postprocessing?.fog_params;
|
||||
|
||||
const dof = !!molstar_postprocessing?.enable_depth_of_field;
|
||||
const dofParams = molstar_postprocessing?.depth_of_field_params;
|
||||
|
||||
const bloom = !!molstar_postprocessing?.enable_bloom;
|
||||
const bloomParams = molstar_postprocessing?.bloom_params;
|
||||
|
||||
return {
|
||||
...oldCanvasProps,
|
||||
postprocessing: {
|
||||
...oldCanvasProps.postprocessing,
|
||||
outline: outline
|
||||
? { name: 'on', params: ParamDefinition.getDefaultValues(OutlineParams) }
|
||||
? { name: 'on', params: { ...ParamDefinition.getDefaultValues(OutlineParams), ...outlineParams } }
|
||||
: oldCanvasProps.postprocessing.outline,
|
||||
shadow: shadow
|
||||
? { name: 'on', params: ParamDefinition.getDefaultValues(ShadowParams) }
|
||||
? { name: 'on', params: { ...ParamDefinition.getDefaultValues(ShadowParams), ...shadowParams } }
|
||||
: oldCanvasProps.postprocessing.shadow,
|
||||
occlusion: occlusion
|
||||
? { name: 'on', params: ParamDefinition.getDefaultValues(SsaoParams) }
|
||||
? { name: 'on', params: { ...ParamDefinition.getDefaultValues(SsaoParams), ...occlusionParams } }
|
||||
: oldCanvasProps.postprocessing.occlusion,
|
||||
dof: dof
|
||||
? { name: 'on', params: { ...ParamDefinition.getDefaultValues(DofParams), ...dofParams } }
|
||||
: oldCanvasProps.postprocessing.dof,
|
||||
bloom: bloom
|
||||
? { name: 'on', params: { ...ParamDefinition.getDefaultValues(BloomParams), ...bloomParams } }
|
||||
: oldCanvasProps.postprocessing.bloom,
|
||||
},
|
||||
cameraFog: fog
|
||||
? { name: 'on', params: { ...ParamDefinition.getDefaultValues(CameraFogParams), ...fogParams } }
|
||||
: oldCanvasProps.cameraFog,
|
||||
renderer: {
|
||||
...oldCanvasProps.renderer,
|
||||
backgroundColor: backgroundColor,
|
||||
|
||||
@@ -39,8 +39,9 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { capitalize } from '../../../mol-util/string';
|
||||
import { rowsToExpression, rowToExpression } from '../helpers/selections';
|
||||
import { collectMVSReferences, decodeColor, isDefined } from '../helpers/utils';
|
||||
import { MolstarNode, MolstarSubtree } from '../tree/molstar/molstar-tree';
|
||||
import { MVSNode } from '../tree/mvs/mvs-tree';
|
||||
import { addParamDefaults } from '../tree/generic/params-schema';
|
||||
import { MolstarNode, MolstarNodeParams, MolstarSubtree } from '../tree/molstar/molstar-tree';
|
||||
import { MVSNode, MVSTreeSchema } from '../tree/mvs/mvs-tree';
|
||||
import { isComponentExpression, isPrimitiveComponentExpressions, isVector3, PrimitivePositionT } from '../tree/mvs/param-types';
|
||||
import { MVSTransform } from './annotation-structure-component';
|
||||
|
||||
@@ -97,6 +98,16 @@ export const MVSDownloadPrimitiveData = MVSTransform({
|
||||
},
|
||||
});
|
||||
|
||||
/* Cannot use MolstarSubtree<'primitives'>> because information about type of children would be lost and cause TypeScript errors in dependent code */
|
||||
interface PrimitivesSubtree {
|
||||
kind: 'primitives',
|
||||
params: MolstarNodeParams<'primitives'>,
|
||||
children?: {
|
||||
kind: 'primitive',
|
||||
params: MolstarNodeParams<'primitive'>,
|
||||
}[],
|
||||
}
|
||||
|
||||
export type MVSInlinePrimitiveData = typeof MVSInlinePrimitiveData
|
||||
export const MVSInlinePrimitiveData = MVSTransform({
|
||||
name: 'mvs-inline-primitive-data',
|
||||
@@ -104,7 +115,10 @@ export const MVSInlinePrimitiveData = MVSTransform({
|
||||
from: [SO.Root, SO.Molecule.Structure],
|
||||
to: MVSPrimitivesData,
|
||||
params: {
|
||||
node: PD.Value<MolstarSubtree<'primitives'>>(undefined as any, { isHidden: true }),
|
||||
node: PD.Value<PrimitivesSubtree>({
|
||||
kind: 'primitives',
|
||||
params: addParamDefaults(MVSTreeSchema.nodes.primitives.params, {}),
|
||||
}, { isHidden: true }),
|
||||
},
|
||||
})({
|
||||
apply({ a, params }) {
|
||||
@@ -140,11 +154,12 @@ export const MVSBuildPrimitiveShape = MVSTransform({
|
||||
if (params.kind === 'mesh') {
|
||||
if (!hasPrimitiveKind(a.data, 'mesh')) return StateObject.Null;
|
||||
|
||||
const customMeshParams = a.data.node.custom?.molstar_mesh_params;
|
||||
return new SO.Shape.Provider({
|
||||
label,
|
||||
data: context,
|
||||
params: {
|
||||
...PD.withDefaults(Mesh.Params, { alpha: a.data.options?.opacity ?? 1 }),
|
||||
...PD.withDefaults(Mesh.Params, { alpha: a.data.options?.opacity ?? 1, ...customMeshParams }),
|
||||
...snapshotKey,
|
||||
},
|
||||
getShape: (_, data, __, prev: any) => buildPrimitiveMesh(data, prev?.geometry),
|
||||
@@ -155,6 +170,7 @@ export const MVSBuildPrimitiveShape = MVSTransform({
|
||||
|
||||
const options = a.data.options;
|
||||
const bgColor = options?.label_background_color;
|
||||
const customLabelParams = a.data.node.custom?.molstar_label_params;
|
||||
return new SO.Shape.Provider({
|
||||
label,
|
||||
data: context,
|
||||
@@ -166,6 +182,7 @@ export const MVSBuildPrimitiveShape = MVSTransform({
|
||||
tetherLength: options?.label_tether_length ?? 1,
|
||||
background: isDefined(bgColor),
|
||||
backgroundColor: isDefined(bgColor) ? decodeColor(bgColor) : undefined,
|
||||
...customLabelParams,
|
||||
}),
|
||||
...snapshotKey,
|
||||
},
|
||||
@@ -175,11 +192,12 @@ export const MVSBuildPrimitiveShape = MVSTransform({
|
||||
} else if (params.kind === 'lines') {
|
||||
if (!hasPrimitiveKind(a.data, 'line')) return StateObject.Null;
|
||||
|
||||
const customLineParams = a.data.node.custom?.molstar_line_params;
|
||||
return new SO.Shape.Provider({
|
||||
label,
|
||||
data: context,
|
||||
params: {
|
||||
...PD.withDefaults(Lines.Params, { alpha: a.data.options?.opacity ?? 1 }),
|
||||
...PD.withDefaults(Lines.Params, { alpha: a.data.options?.opacity ?? 1, ...customLineParams }),
|
||||
...snapshotKey,
|
||||
},
|
||||
getShape: (_, data, __, prev: any) => buildPrimitiveLines(data, prev?.geometry),
|
||||
|
||||
@@ -312,7 +312,7 @@ const MolstarLoadingActions: LoadingActions<MolstarTree, MolstarLoadingContext>
|
||||
},
|
||||
primitives(updateParent: UpdateTarget, tree: MolstarSubtree<'primitives'>, context: MolstarLoadingContext): UpdateTarget {
|
||||
const refs = getPrimitiveStructureRefs(tree);
|
||||
const data = UpdateTarget.apply(updateParent, MVSInlinePrimitiveData, { node: tree });
|
||||
const data = UpdateTarget.apply(updateParent, MVSInlinePrimitiveData, { node: tree as any });
|
||||
return applyPrimitiveVisuals(data, refs);
|
||||
},
|
||||
primitives_from_uri(updateParent: UpdateTarget, tree: MolstarNode<'primitives_from_uri'>, context: MolstarLoadingContext): UpdateTarget {
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
*/
|
||||
|
||||
import * as iots from 'io-ts';
|
||||
import { PathReporter } from "io-ts/lib/PathReporter.js";
|
||||
import { onelinerJsonString } from '../../../../mol-util/json';
|
||||
|
||||
|
||||
/** All types that can be used in tree node params.
|
||||
* Can be extended, this is just to list them all in one place and possibly catch some typing errors */
|
||||
type AllowedValueTypes = string | number | boolean | null | [number, number, number] | string[] | number[] | {};
|
||||
@@ -142,6 +140,41 @@ export function fieldValidationIssues<F extends Field>(field: F, value: any): st
|
||||
if (validation._tag === 'Right') {
|
||||
return undefined;
|
||||
} else {
|
||||
return PathReporter.report(validation);
|
||||
return reportErrors(validation.left);
|
||||
}
|
||||
}
|
||||
|
||||
// Inlining `reportErrors` instead of `import { PathReporter } from 'io-ts/PathReporter'`;
|
||||
// because it breaks Deno usage.
|
||||
|
||||
function reportErrors(errors: iots.Errors): string[] | undefined {
|
||||
if (errors.length === 0) return undefined;
|
||||
return errors.map(getMessage);
|
||||
}
|
||||
|
||||
function getMessage(e: iots.ValidationError) {
|
||||
return e.message !== undefined
|
||||
? e.message
|
||||
: `Invalid value ${stringifyError(e.value)} supplied to ${getContextPath(e.context)}`;
|
||||
}
|
||||
|
||||
function getContextPath(context: iots.ValidationError['context']) {
|
||||
return context.map(a => `${a.key}: ${a.type.name}`).join('/');
|
||||
}
|
||||
|
||||
function getFunctionName(f: Function & { displayName?: string }) {
|
||||
return f.displayName || f.name || `<function ${f.length}>`;
|
||||
}
|
||||
|
||||
function stringifyError(v: any) {
|
||||
if (typeof v === 'function') {
|
||||
return getFunctionName(v);
|
||||
}
|
||||
if (typeof v === 'number' && !isFinite(v)) {
|
||||
if (isNaN(v)) {
|
||||
return 'NaN';
|
||||
}
|
||||
return v > 0 ? 'Infinity' : '-Infinity';
|
||||
}
|
||||
return JSON.stringify(v);
|
||||
}
|
||||
@@ -50,6 +50,9 @@ import { isMobileBrowser } from '../mol-util/browser';
|
||||
import { Ray3D } from '../mol-math/geometry/primitives/ray3d';
|
||||
import { RayHelper } from './helper/ray-helper';
|
||||
|
||||
export const CameraFogParams = {
|
||||
intensity: PD.Numeric(15, { min: 1, max: 100, step: 1 }),
|
||||
};
|
||||
export const Canvas3DParams = {
|
||||
camera: PD.Group({
|
||||
mode: PD.Select('perspective', PD.arrayToOptions(['perspective', 'orthographic'] as const), { label: 'Camera' }),
|
||||
@@ -63,9 +66,7 @@ export const Canvas3DParams = {
|
||||
manualReset: PD.Boolean(false, { isHidden: true }),
|
||||
}, { pivot: 'mode' }),
|
||||
cameraFog: PD.MappedStatic('on', {
|
||||
on: PD.Group({
|
||||
intensity: PD.Numeric(15, { min: 1, max: 100, step: 1 }),
|
||||
}),
|
||||
on: PD.Group(CameraFogParams),
|
||||
off: PD.Group({})
|
||||
}, { cycle: true, description: 'Show fog in the distance' }),
|
||||
cameraClipping: PD.Group({
|
||||
|
||||
@@ -8,6 +8,8 @@ import { getCellBoundingSphere } from '../../mol-plugin-state/manager/focus-came
|
||||
import { PluginStateObject } from '../../mol-plugin-state/objects';
|
||||
import { StateObjectCell } from '../../mol-state';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { Script } from '../../mol-script/script';
|
||||
import { QueryContext, QueryFn, StructureElement, StructureSelection } from '../../mol-model/structure';
|
||||
|
||||
export type MarkdownExtensionEvent = 'click' | 'mouse-enter' | 'mouse-leave';
|
||||
|
||||
@@ -82,6 +84,72 @@ export const BuiltInMarkdownExtension: MarkdownExtension[] = [
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'query',
|
||||
execute: ({ event, args, manager }) => {
|
||||
const expression = args['query'];
|
||||
if (!expression?.length) return;
|
||||
|
||||
// supported languages: mol-script, pymol, vmd, jmol
|
||||
const language = args['lang'] || 'mol-script';
|
||||
// supported actions: highlight, focus
|
||||
const action = parseArray(args['action'] || 'highlight');
|
||||
const focusRadius = parseFloat(args['focus-radius'] || '3');
|
||||
|
||||
if (event === 'mouse-leave') {
|
||||
if (action.includes('highlight')) {
|
||||
manager.plugin.managers.interactivity.lociHighlights.clearHighlights();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let query: QueryFn<StructureSelection>;
|
||||
try {
|
||||
query = Script.toQuery({
|
||||
language: language as Script.Language,
|
||||
expression
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(`Failed to parse query '${expression}' (${language})`, e);
|
||||
return;
|
||||
}
|
||||
|
||||
const structures = manager.plugin.state.data.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Structure));
|
||||
|
||||
if (event === 'mouse-enter') {
|
||||
if (!action.includes('focus')) {
|
||||
return;
|
||||
}
|
||||
manager.plugin.managers.interactivity.lociHighlights.clearHighlights();
|
||||
for (const structure of structures) {
|
||||
if (!structure.obj?.data) continue;
|
||||
const selection = query(new QueryContext(structure.obj.data));
|
||||
const loci = StructureSelection.toLociWithSourceUnits(selection);
|
||||
manager.plugin.managers.interactivity.lociHighlights.highlight({
|
||||
loci,
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (event === 'click') {
|
||||
if (!action.includes('focus')) {
|
||||
return;
|
||||
}
|
||||
const spheres = structures.map(s => {
|
||||
if (!s.obj?.data) return undefined;
|
||||
const selection = query(new QueryContext(s.obj.data));
|
||||
if (StructureSelection.isEmpty(selection)) return;
|
||||
|
||||
const loci = StructureSelection.toLociWithSourceUnits(selection);
|
||||
return StructureElement.Loci.getBoundary(loci).sphere;
|
||||
}).filter(s => !!s);
|
||||
|
||||
if (spheres.length) {
|
||||
manager.plugin.managers.camera.focusSpheres(spheres, s => s, { extraRadius: focusRadius });
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export class MarkdownExtensionManager {
|
||||
|
||||
Reference in New Issue
Block a user