react-cheminfo 0.39.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/check-deploy.mjs +4 -2
- package/lib/deploy/core/checkDeploy.d.ts +3 -1
- package/lib/deploy/core/checkDeploy.d.ts.map +1 -1
- package/lib/deploy/core/checkDeploy.js +8 -2
- package/lib/deploy/core/checkDeploy.js.map +1 -1
- package/lib/deploy/core/index.d.ts +1 -0
- package/lib/deploy/core/index.d.ts.map +1 -1
- package/lib/deploy/core/index.js +1 -0
- package/lib/deploy/core/index.js.map +1 -1
- package/lib/deploy/core/publishedImage.d.ts +30 -0
- package/lib/deploy/core/publishedImage.d.ts.map +1 -0
- package/lib/deploy/core/publishedImage.js +96 -0
- package/lib/deploy/core/publishedImage.js.map +1 -0
- package/lib/deploy/core/types.d.ts +1 -1
- package/lib/deploy/core/types.d.ts.map +1 -1
- package/lib/deploy/core/types.js.map +1 -1
- package/lib/molecule3d/ui/Molecule3DToolbar.d.ts +9 -7
- package/lib/molecule3d/ui/Molecule3DToolbar.d.ts.map +1 -1
- package/lib/molecule3d/ui/Molecule3DToolbar.js +13 -8
- package/lib/molecule3d/ui/Molecule3DToolbar.js.map +1 -1
- package/lib/molecule3d/ui/MoleculeCanvas3D.js +1 -1
- package/lib/molecule3d/ui/MoleculeCanvas3D.js.map +1 -1
- package/lib/molecule3d/ui/camera.d.ts +0 -11
- package/lib/molecule3d/ui/camera.d.ts.map +1 -1
- package/lib/molecule3d/ui/camera.js +6 -80
- package/lib/molecule3d/ui/camera.js.map +1 -1
- package/lib/molecule3d/ui/exportMoleculeImage.d.ts +6 -2
- package/lib/molecule3d/ui/exportMoleculeImage.d.ts.map +1 -1
- package/lib/molecule3d/ui/exportMoleculeImage.js.map +1 -1
- package/lib/molecule3d/ui/index.d.ts +9 -0
- package/lib/molecule3d/ui/index.d.ts.map +1 -1
- package/lib/molecule3d/ui/index.js +5 -0
- package/lib/molecule3d/ui/index.js.map +1 -1
- package/lib/molecule3d/ui/measurements.d.ts +22 -2
- package/lib/molecule3d/ui/measurements.d.ts.map +1 -1
- package/lib/molecule3d/ui/measurements.js +25 -3
- package/lib/molecule3d/ui/measurements.js.map +1 -1
- package/lib/molecule3d/ui/useImageExport.d.ts +2 -2
- package/lib/molecule3d/ui/useImageExport.d.ts.map +1 -1
- package/lib/molecule3d/ui/useImageExport.js.map +1 -1
- package/lib/molecule3d/ui/viewer.d.ts.map +1 -1
- package/lib/molecule3d/ui/viewer.js +16 -49
- package/lib/molecule3d/ui/viewer.js.map +1 -1
- package/lib/molstar/core/camera.d.ts +37 -0
- package/lib/molstar/core/camera.d.ts.map +1 -0
- package/lib/molstar/core/camera.js +49 -0
- package/lib/molstar/core/camera.js.map +1 -0
- package/lib/molstar/core/cameraPose.d.ts +54 -0
- package/lib/molstar/core/cameraPose.d.ts.map +1 -0
- package/lib/molstar/core/cameraPose.js +78 -0
- package/lib/molstar/core/cameraPose.js.map +1 -0
- package/lib/molstar/core/hover.d.ts +49 -0
- package/lib/molstar/core/hover.d.ts.map +1 -0
- package/lib/molstar/core/hover.js +91 -0
- package/lib/molstar/core/hover.js.map +1 -0
- package/lib/molstar/core/index.d.ts +7 -0
- package/lib/molstar/core/index.d.ts.map +1 -0
- package/lib/molstar/core/index.js +5 -0
- package/lib/molstar/core/index.js.map +1 -0
- package/lib/molstar/core/plugin.d.ts +80 -0
- package/lib/molstar/core/plugin.d.ts.map +1 -0
- package/lib/molstar/core/plugin.js +125 -0
- package/lib/molstar/core/plugin.js.map +1 -0
- package/lib/molstar.d.ts +18 -0
- package/lib/molstar.d.ts.map +1 -0
- package/lib/molstar.js +17 -0
- package/lib/molstar.js.map +1 -0
- package/lib/share/ui/SharePreview.d.ts.map +1 -1
- package/lib/share/ui/SharePreview.js +25 -0
- package/lib/share/ui/SharePreview.js.map +1 -1
- package/lib/share/ui/useShareRegionReports.d.ts.map +1 -1
- package/lib/share/ui/useShareRegionReports.js +41 -12
- package/lib/share/ui/useShareRegionReports.js.map +1 -1
- package/lib/structure/ui/ConformerTable.d.ts +8 -0
- package/lib/structure/ui/ConformerTable.d.ts.map +1 -1
- package/lib/structure/ui/ConformerTable.js +24 -4
- package/lib/structure/ui/ConformerTable.js.map +1 -1
- package/package.json +2 -1
- package/src/deploy/core/checkDeploy.ts +14 -2
- package/src/deploy/core/index.ts +5 -0
- package/src/deploy/core/publishedImage.ts +110 -0
- package/src/deploy/core/types.ts +3 -1
- package/src/molecule3d/ui/Molecule3DToolbar.tsx +23 -16
- package/src/molecule3d/ui/MoleculeCanvas3D.tsx +1 -1
- package/src/molecule3d/ui/camera.ts +18 -93
- package/src/molecule3d/ui/exportMoleculeImage.ts +6 -2
- package/src/molecule3d/ui/index.ts +12 -0
- package/src/molecule3d/ui/measurements.ts +42 -3
- package/src/molecule3d/ui/useImageExport.ts +2 -2
- package/src/molecule3d/ui/viewer.ts +21 -51
- package/src/molstar/core/camera.ts +61 -0
- package/src/molstar/core/cameraPose.ts +126 -0
- package/src/molstar/core/hover.ts +109 -0
- package/src/molstar/core/index.ts +13 -0
- package/src/molstar/core/plugin.ts +159 -0
- package/src/molstar.ts +22 -0
- package/src/share/ui/SharePreview.tsx +31 -0
- package/src/share/ui/useShareRegionReports.ts +39 -15
- package/src/structure/ui/ConformerTable.tsx +38 -4
- package/lib/molecule3d/ui/viewerSpec.d.ts +0 -17
- package/lib/molecule3d/ui/viewerSpec.d.ts.map +0 -1
- package/lib/molecule3d/ui/viewerSpec.js +0 -34
- package/lib/molecule3d/ui/viewerSpec.js.map +0 -1
- package/src/molecule3d/ui/viewerSpec.ts +0 -38
|
@@ -32,7 +32,7 @@ import { CONFORMER_COLUMN_LABELS, NUMERIC_CONFORMER_COLUMNS, PICKER_COLUMNS, } f
|
|
|
32
32
|
* @returns The table, or `null` when there is nothing to show.
|
|
33
33
|
*/
|
|
34
34
|
export function ConformerTable(props) {
|
|
35
|
-
const { conformers, columns = PICKER_COLUMNS, ranking = 'force-field', selectedId = null, onSelect, temperature = ROOM_TEMPERATURE, label = 'Conformers, most stable first', rowName = String, columnLabels, } = props;
|
|
35
|
+
const { conformers, columns = PICKER_COLUMNS, ranking = 'force-field', selectedId = null, onSelect, temperature = ROOM_TEMPERATURE, label = 'Conformers, most stable first', rowName = String, columnLabels, provisional = false, } = props;
|
|
36
36
|
const bodyRef = useRef(null);
|
|
37
37
|
const shares = useMemo(() => {
|
|
38
38
|
if (!columns.includes('population'))
|
|
@@ -93,7 +93,7 @@ export function ConformerTable(props) {
|
|
|
93
93
|
return copyableHere &&
|
|
94
94
|
COPY_LABELS[column] !== undefined &&
|
|
95
95
|
typeof content === 'string' &&
|
|
96
|
-
content !== '—' ? (_jsx(ClickToCopy, { as: "td", style: cellStyle(column), value: content, label: COPY_LABELS[column], testId: CELL_TEST_IDS[column], children: content }, column)) : (_jsx("td", { style: cellStyle(column), "data-testid": CELL_TEST_IDS[column], children: content }, column));
|
|
96
|
+
content !== '—' ? (_jsx(ClickToCopy, { as: "td", style: cellStyle(column, provisional), value: content, label: COPY_LABELS[column], testId: CELL_TEST_IDS[column], children: content }, column)) : (_jsx("td", { style: cellStyle(column, provisional), "data-testid": CELL_TEST_IDS[column], children: content }, column));
|
|
97
97
|
}) }, conformer.id));
|
|
98
98
|
}) })] }));
|
|
99
99
|
}
|
|
@@ -200,14 +200,34 @@ const ENERGY_RESOLUTION = 0.005;
|
|
|
200
200
|
function headerStyle(column) {
|
|
201
201
|
return NUMERIC_CONFORMER_COLUMNS.has(column) ? numericStyle : undefined;
|
|
202
202
|
}
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
/**
|
|
204
|
+
* A cell's own style: numbers are right-aligned and tabular, and every cell a
|
|
205
|
+
* better method will restate is muted while it works. The rank is not one of
|
|
206
|
+
* them — it names the row rather than measuring it, and it is what a reader
|
|
207
|
+
* follows as the order changes under them.
|
|
208
|
+
* @param column - The column the cell is in.
|
|
209
|
+
* @param provisional - Whether the energies are still expected to change.
|
|
210
|
+
* @returns The cell's inline style, or `undefined` when it needs none.
|
|
211
|
+
*/
|
|
212
|
+
function cellStyle(column, provisional) {
|
|
213
|
+
const numeric = NUMERIC_CONFORMER_COLUMNS.has(column);
|
|
214
|
+
if (!provisional || column === 'id') {
|
|
215
|
+
return numeric ? numericStyle : undefined;
|
|
216
|
+
}
|
|
217
|
+
return numeric ? provisionalNumericStyle : provisionalStyle;
|
|
205
218
|
}
|
|
206
219
|
const tableStyle = { width: '100%' };
|
|
207
220
|
const numericStyle = {
|
|
208
221
|
textAlign: 'right',
|
|
209
222
|
fontVariantNumeric: 'tabular-nums',
|
|
210
223
|
};
|
|
224
|
+
const provisionalStyle = {
|
|
225
|
+
color: 'var(--text-muted)',
|
|
226
|
+
};
|
|
227
|
+
const provisionalNumericStyle = {
|
|
228
|
+
...numericStyle,
|
|
229
|
+
...provisionalStyle,
|
|
230
|
+
};
|
|
211
231
|
/**
|
|
212
232
|
* The selected row is tinted with the site's own accent, so the table belongs
|
|
213
233
|
* to whichever site draws it; a row is a pointer only where a click does
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConformerTable.js","sourceRoot":"","sources":["../../../src/structure/ui/ConformerTable.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAoC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EACL,gBAAgB,EAChB,eAAe,GAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAI7E,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,cAAc,GACf,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"ConformerTable.js","sourceRoot":"","sources":["../../../src/structure/ui/ConformerTable.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-cheminfo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React components, hooks and framework-free helpers shared by the cheminfo sites: site chrome, citations, sharing, routing, pedagogy, charts, and the structure, orbital and 3D molecule viewers",
|
|
6
6
|
"author": "Luc Patiny",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"./core": "./lib/core.js",
|
|
21
21
|
"./ir": "./lib/ir.js",
|
|
22
22
|
"./molecule3d": "./lib/molecule3d.js",
|
|
23
|
+
"./molstar": "./lib/molstar.js",
|
|
23
24
|
"./orbital": "./lib/orbital.js",
|
|
24
25
|
"./slides": "./lib/slides.js",
|
|
25
26
|
"./spectra": "./lib/spectra.js",
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { readComposeFile } from './composeFile.ts';
|
|
2
2
|
import { readEnvExample } from './envExample.ts';
|
|
3
3
|
import { readPageCache } from './pageCache.ts';
|
|
4
|
+
import {
|
|
5
|
+
DOCKER_IMAGE_WORKFLOW,
|
|
6
|
+
readInstallRetries,
|
|
7
|
+
readPublishedImage,
|
|
8
|
+
} from './publishedImage.ts';
|
|
4
9
|
import type { CheckDeployOptions, DeployFile, DeployProblem } from './types.ts';
|
|
5
10
|
import { DEPLOY_COMPOSE_FILES } from './types.ts';
|
|
6
11
|
|
|
@@ -13,7 +18,9 @@ import { DEPLOY_COMPOSE_FILES } from './types.ts';
|
|
|
13
18
|
* reports it healthy. So a repository has to hand it a selectable tag on every
|
|
14
19
|
* image we build, an `IMAGE_NAME` that names the package our own workflow
|
|
15
20
|
* publishes, a compose file that parses on a checkout with no `.env` yet, and a
|
|
16
|
-
* health probe to read. It also has to
|
|
21
|
+
* health probe to read. It also has to publish that image in the first place:
|
|
22
|
+
* with no `latest` to pull the script builds from source on the deploy host,
|
|
23
|
+
* and the install that follows must survive a blip in the registry. It also has to hand the browser a page the browser will
|
|
17
24
|
* not keep, or the next deploy leaves returning visitors on a blank one. Each
|
|
18
25
|
* of those is invisible until a deploy, which is the
|
|
19
26
|
* worst moment to discover it — an `env_file` without `required: false` fails
|
|
@@ -72,7 +79,12 @@ export function findDeployProblems(
|
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
const dockerfile = byPath.get('Dockerfile');
|
|
75
|
-
if (dockerfile !== undefined)
|
|
82
|
+
if (dockerfile !== undefined) {
|
|
83
|
+
readPageCache(dockerfile, byPath, problems);
|
|
84
|
+
readInstallRetries(dockerfile, problems);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
readPublishedImage(byPath.get(DOCKER_IMAGE_WORKFLOW), problems);
|
|
76
88
|
|
|
77
89
|
const gitignore = byPath.get('.gitignore');
|
|
78
90
|
if (gitignore === undefined || !/^\s*\/?\.deploy\/?\s*$/m.test(gitignore)) {
|
package/src/deploy/core/index.ts
CHANGED
|
@@ -6,4 +6,9 @@ export type {
|
|
|
6
6
|
DeployProblemKind,
|
|
7
7
|
} from './types.ts';
|
|
8
8
|
export { NGINX_CONFIG, PAGE_CACHE_CONFIG } from './pageCache.ts';
|
|
9
|
+
export {
|
|
10
|
+
DOCKER_IMAGE_WORKFLOW,
|
|
11
|
+
readInstallRetries,
|
|
12
|
+
readPublishedImage,
|
|
13
|
+
} from './publishedImage.ts';
|
|
9
14
|
export { DEPLOY_COMPOSE_FILES } from './types.ts';
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { DeployProblem } from './types.ts';
|
|
2
|
+
|
|
3
|
+
/** The workflow that publishes this repository's image, at its fixed path. */
|
|
4
|
+
export const DOCKER_IMAGE_WORKFLOW = '.github/workflows/docker-image.yml';
|
|
5
|
+
|
|
6
|
+
const TAG_VERSION = /^\s*tag-version:\s*(?<value>.+?)\s*$/m;
|
|
7
|
+
const INSTALL = /^\s*RUN\s+npm\s+ci\b/;
|
|
8
|
+
const RETRIES = /^\s*ENV\s+.*\bNPM_CONFIG_FETCH_RETRIES=/;
|
|
9
|
+
const STAGE = /^\s*FROM\s+/i;
|
|
10
|
+
// Written with an escaped brace so it is not read as an interpolation here.
|
|
11
|
+
const GUARDED = `\${{ github.event_name == 'push' && github.ref_name || '' }}`;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Report a repository whose image is never published with a `latest` tag.
|
|
15
|
+
*
|
|
16
|
+
* The shared workflow derives `:<version>`, `:<major>.<minor>`, `:<major>` and
|
|
17
|
+
* `:latest` from `tag-version` alone; given nothing it publishes a single
|
|
18
|
+
* `:HEAD` and no `latest`. Compose files default to `${IMAGE_TAG:-latest}`, so
|
|
19
|
+
* the deploy then has nothing to pull and builds the image on the deploy host
|
|
20
|
+
* instead — which is how a registry blip, a build timeout or an out-of-memory
|
|
21
|
+
* kill becomes an outage, reported against npm rather than against the missing
|
|
22
|
+
* tag. The workflow, the release and the push all succeed, so nothing says so.
|
|
23
|
+
* @param workflow - The docker-image workflow, or undefined when there is none.
|
|
24
|
+
* @param problems - Where each problem found is appended.
|
|
25
|
+
*/
|
|
26
|
+
export function readPublishedImage(
|
|
27
|
+
workflow: string | undefined,
|
|
28
|
+
problems: DeployProblem[],
|
|
29
|
+
): void {
|
|
30
|
+
if (workflow === undefined) {
|
|
31
|
+
problems.push({
|
|
32
|
+
file: DOCKER_IMAGE_WORKFLOW,
|
|
33
|
+
line: 0,
|
|
34
|
+
kind: 'unpublishable-image',
|
|
35
|
+
message:
|
|
36
|
+
'nothing publishes an image, so every deploy builds one on the server',
|
|
37
|
+
hint: 'add docker-image.yml, calling the shared workflow on a v* tag with a guarded tag-version',
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const match = TAG_VERSION.exec(workflow);
|
|
43
|
+
if (match?.groups === undefined) {
|
|
44
|
+
problems.push({
|
|
45
|
+
file: DOCKER_IMAGE_WORKFLOW,
|
|
46
|
+
line: lineOf(workflow, /docker-image\.yml@docker-image/),
|
|
47
|
+
kind: 'unpublishable-image',
|
|
48
|
+
message:
|
|
49
|
+
'no tag-version, so the package gets a single :HEAD and no :latest for a compose file to pull',
|
|
50
|
+
hint: `with: tag-version: ${GUARDED}`,
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const value = match.groups.value ?? '';
|
|
56
|
+
if (value.includes('github.ref_name') && !value.includes('event_name')) {
|
|
57
|
+
problems.push({
|
|
58
|
+
file: DOCKER_IMAGE_WORKFLOW,
|
|
59
|
+
line: lineOf(workflow, TAG_VERSION),
|
|
60
|
+
kind: 'unpublishable-image',
|
|
61
|
+
message:
|
|
62
|
+
'tag-version is the bare ref, which on a manual run is a branch name split as if it were a semver',
|
|
63
|
+
hint: `guard it: ${GUARDED}`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Report a build stage that installs with npm's own patience.
|
|
70
|
+
*
|
|
71
|
+
* A deploy with no image to pull builds from source on the deploy host, so the
|
|
72
|
+
* whole dependency closure comes over the network at the one moment nothing may
|
|
73
|
+
* fail. npm's two default retries are capped at a minute and spent in under
|
|
74
|
+
* twenty seconds, which is short enough that an ordinary blip reads as a broken
|
|
75
|
+
* repository — so each stage that installs says how long it is willing to try.
|
|
76
|
+
* @param dockerfile - The Dockerfile.
|
|
77
|
+
* @param problems - Where each problem found is appended.
|
|
78
|
+
*/
|
|
79
|
+
export function readInstallRetries(
|
|
80
|
+
dockerfile: string,
|
|
81
|
+
problems: DeployProblem[],
|
|
82
|
+
): void {
|
|
83
|
+
const lines = dockerfile.split('\n');
|
|
84
|
+
let patient = false;
|
|
85
|
+
for (let index = 0; index < lines.length; index++) {
|
|
86
|
+
const line = lines[index] ?? '';
|
|
87
|
+
// ENV does not cross a FROM, so each stage answers for itself.
|
|
88
|
+
if (STAGE.test(line)) {
|
|
89
|
+
patient = false;
|
|
90
|
+
} else if (RETRIES.test(line)) {
|
|
91
|
+
patient = true;
|
|
92
|
+
} else if (INSTALL.test(line) && !patient) {
|
|
93
|
+
problems.push({
|
|
94
|
+
file: 'Dockerfile',
|
|
95
|
+
line: index + 1,
|
|
96
|
+
kind: 'brittle-install',
|
|
97
|
+
message:
|
|
98
|
+
"npm ci installs with npm's two default retries, so a network blip of twenty seconds fails the deploy",
|
|
99
|
+
hint: 'ENV NPM_CONFIG_FETCH_RETRIES=5 NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT=120000 above it, in this stage',
|
|
100
|
+
});
|
|
101
|
+
patient = true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function lineOf(text: string, pattern: RegExp): number {
|
|
107
|
+
const match = pattern.exec(text);
|
|
108
|
+
if (match === null) return 0;
|
|
109
|
+
return text.slice(0, match.index).split('\n').length;
|
|
110
|
+
}
|
package/src/deploy/core/types.ts
CHANGED
|
@@ -10,7 +10,9 @@ export type DeployProblemKind =
|
|
|
10
10
|
| 'missing-healthcheck'
|
|
11
11
|
| 'missing-env-example'
|
|
12
12
|
| 'missing-deploy-ignore'
|
|
13
|
-
| 'cacheable-page'
|
|
13
|
+
| 'cacheable-page'
|
|
14
|
+
| 'unpublishable-image'
|
|
15
|
+
| 'brittle-install';
|
|
14
16
|
|
|
15
17
|
/** One way a repository would fail, or silently mis-deploy, on the server. */
|
|
16
18
|
export interface DeployProblem {
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
MEASUREMENT_LABELS,
|
|
18
18
|
} from '../core/measurement.ts';
|
|
19
19
|
import type { Molecule3DTools } from '../core/settings.ts';
|
|
20
|
+
import { resolveMolecule3DTools } from '../core/settings.ts';
|
|
20
21
|
|
|
21
22
|
import { Molecule3DHelp } from './Molecule3DHelp.tsx';
|
|
22
23
|
import {
|
|
@@ -27,20 +28,22 @@ import {
|
|
|
27
28
|
|
|
28
29
|
/** Props of {@link Molecule3DToolbar}. */
|
|
29
30
|
export interface Molecule3DToolbarProps {
|
|
30
|
-
tools
|
|
31
|
+
/** Which tools to show; every one it does not name is on. */
|
|
32
|
+
tools?: Partial<Molecule3DTools>;
|
|
31
33
|
measureKind: MeasurementKind | null;
|
|
32
34
|
onMeasureKindChange: (kind: MeasurementKind | null) => void;
|
|
33
35
|
measurementCount: number;
|
|
34
36
|
onClearMeasurements: () => void;
|
|
35
37
|
spinning: boolean;
|
|
36
38
|
onSpinningChange: (spinning: boolean) => void;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
/** Whether the molecular surface is drawn; its tool is left out without a handler. */
|
|
40
|
+
showSurface?: boolean;
|
|
41
|
+
onShowSurfaceChange?: (showSurface: boolean) => void;
|
|
39
42
|
onResetView: () => void;
|
|
40
|
-
/** Content of the options popover. */
|
|
41
|
-
options
|
|
42
|
-
/** Content of the export popover. */
|
|
43
|
-
exportPanel
|
|
43
|
+
/** Content of the options popover; its tool is left out without one. */
|
|
44
|
+
options?: ReactElement;
|
|
45
|
+
/** Content of the export popover; its tool is left out without one. */
|
|
46
|
+
exportPanel?: ReactElement;
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
/**
|
|
@@ -50,7 +53,7 @@ export interface Molecule3DToolbarProps {
|
|
|
50
53
|
*/
|
|
51
54
|
export function Molecule3DToolbar(props: Molecule3DToolbarProps): ReactElement {
|
|
52
55
|
const {
|
|
53
|
-
tools,
|
|
56
|
+
tools: toolsProp,
|
|
54
57
|
measureKind,
|
|
55
58
|
onMeasureKindChange,
|
|
56
59
|
measurementCount,
|
|
@@ -64,16 +67,20 @@ export function Molecule3DToolbar(props: Molecule3DToolbarProps): ReactElement {
|
|
|
64
67
|
exportPanel,
|
|
65
68
|
} = props;
|
|
66
69
|
const t = useChromeT();
|
|
70
|
+
const tools = resolveMolecule3DTools(toolsProp);
|
|
71
|
+
const showOptions = tools.options && options !== undefined;
|
|
72
|
+
const showSurfaceTool = tools.surface && onShowSurfaceChange !== undefined;
|
|
73
|
+
const showExport = tools.export && exportPanel !== undefined;
|
|
67
74
|
const hasView =
|
|
68
75
|
tools.spin ||
|
|
69
76
|
tools.surface ||
|
|
70
77
|
tools.reset ||
|
|
71
|
-
|
|
72
|
-
|
|
78
|
+
showOptions ||
|
|
79
|
+
showExport ||
|
|
73
80
|
tools.help;
|
|
74
81
|
|
|
75
82
|
return (
|
|
76
|
-
<div style={COLUMN_STYLE}>
|
|
83
|
+
<div className="no-print" style={COLUMN_STYLE}>
|
|
77
84
|
{hasView && (
|
|
78
85
|
<Card elevation={1} style={CARD_STYLE}>
|
|
79
86
|
<Toolbar vertical aria-label={t('molecule3d.view')}>
|
|
@@ -98,19 +105,19 @@ export function Molecule3DToolbar(props: Molecule3DToolbarProps): ReactElement {
|
|
|
98
105
|
}}
|
|
99
106
|
/>
|
|
100
107
|
)}
|
|
101
|
-
{
|
|
108
|
+
{showSurfaceTool && (
|
|
102
109
|
<Toolbar.Item
|
|
103
110
|
icon={<SurfaceIcon />}
|
|
104
|
-
active={showSurface}
|
|
111
|
+
active={showSurface ?? false}
|
|
105
112
|
aria-label={t('molecule3d.surface')}
|
|
106
113
|
tooltip={t('molecule3d.molecularSurface')}
|
|
107
114
|
tooltipProps={TOOLTIP_PROPS}
|
|
108
115
|
onClick={() => {
|
|
109
|
-
onShowSurfaceChange(
|
|
116
|
+
onShowSurfaceChange(showSurface !== true);
|
|
110
117
|
}}
|
|
111
118
|
/>
|
|
112
119
|
)}
|
|
113
|
-
{
|
|
120
|
+
{showOptions && (
|
|
114
121
|
<Toolbar.PopoverItem
|
|
115
122
|
placement="right-start"
|
|
116
123
|
content={options}
|
|
@@ -122,7 +129,7 @@ export function Molecule3DToolbar(props: Molecule3DToolbarProps): ReactElement {
|
|
|
122
129
|
}}
|
|
123
130
|
/>
|
|
124
131
|
)}
|
|
125
|
-
{
|
|
132
|
+
{showExport && (
|
|
126
133
|
<Toolbar.PopoverItem
|
|
127
134
|
placement="right-start"
|
|
128
135
|
content={exportPanel}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import type { CSSProperties, ReactElement } from 'react';
|
|
9
9
|
import { useEffect, useRef, useState } from 'react';
|
|
10
10
|
|
|
11
|
+
import { DEFAULT_SPIN_SPEED } from '../../molstar/core/index.ts';
|
|
11
12
|
import type { Measurement, MeasurementKind } from '../core/measurement.ts';
|
|
12
13
|
import {
|
|
13
14
|
normalizeMolecule3DSettings,
|
|
@@ -17,7 +18,6 @@ import {
|
|
|
17
18
|
import { Molecule3DExport } from './Molecule3DExport.tsx';
|
|
18
19
|
import { Molecule3DOptions } from './Molecule3DOptions.tsx';
|
|
19
20
|
import { Molecule3DToolbar } from './Molecule3DToolbar.tsx';
|
|
20
|
-
import { DEFAULT_SPIN_SPEED } from './camera.ts';
|
|
21
21
|
import { createMolecule3DViewer } from './createViewer.ts';
|
|
22
22
|
import type { MoleculeViewer3DProps } from './moleculeViewer3DProps.ts';
|
|
23
23
|
import { useControlledState } from './useControlledState.ts';
|
|
@@ -6,53 +6,21 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { Camera } from 'molstar/lib/mol-canvas3d/camera.js';
|
|
9
|
-
import {
|
|
9
|
+
import { Vec3 } from 'molstar/lib/mol-math/linear-algebra.js';
|
|
10
10
|
import type { PluginContext } from 'molstar/lib/mol-plugin/context.js';
|
|
11
11
|
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_CAMERA_DURATION,
|
|
14
|
+
cameraToPose,
|
|
15
|
+
framedRadius,
|
|
16
|
+
poseToCamera,
|
|
17
|
+
} from '../../molstar/core/index.ts';
|
|
12
18
|
import type { Molecule3DCamera } from '../core/camera.ts';
|
|
13
|
-
import { normalizeMolecule3DCamera } from '../core/camera.ts';
|
|
14
|
-
|
|
15
|
-
/** Transition length used when the caller does not pick one, milliseconds. */
|
|
16
|
-
export const DEFAULT_CAMERA_DURATION = 250;
|
|
17
|
-
|
|
18
|
-
/** Turn rate used when the caller does not pick one, in molstar's spin unit. */
|
|
19
|
-
export const DEFAULT_SPIN_SPEED = 1 / 3;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Fraction of the bounding sphere kept as breathing room around the model.
|
|
23
|
-
*
|
|
24
|
-
* `camera.reset()` frames the scene with molstar's own margin, which suits a
|
|
25
|
-
* protein filling a wide viewport and leaves a small molecule a speck in the
|
|
26
|
-
* middle. Framing the visible bounding sphere directly is what makes a single
|
|
27
|
-
* ethanol legible.
|
|
28
|
-
*/
|
|
29
|
-
const FRAMING_MARGIN = 0.08;
|
|
30
|
-
|
|
31
|
-
/** Axis the automatic spin turns about: screen up. */
|
|
32
|
-
const SPIN_AXIS = Vec3.create(0, 1, 0);
|
|
33
|
-
|
|
34
|
-
/** Smallest radius framed, in ångström, so a single atom is not a close-up. */
|
|
35
|
-
const MIN_FRAMING_RADIUS = 0.5;
|
|
36
19
|
|
|
37
20
|
/** Screen up and viewing direction when the model is seen as its file lays it. */
|
|
38
21
|
const FRONT_UP = Vec3.create(0, 1, 0);
|
|
39
22
|
const FRONT_DIRECTION = Vec3.create(0, 0, -1);
|
|
40
23
|
|
|
41
|
-
/** The camera's own axes, which the stored rotation turns into world ones. */
|
|
42
|
-
const CAMERA_UP = Vec3.create(0, 1, 0);
|
|
43
|
-
const CAMERA_BACK = Vec3.create(0, 0, 1);
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* The radius a reset frames, which is the length every stored camera is
|
|
47
|
-
* measured against — so reading a camera and applying it are the same move in
|
|
48
|
-
* opposite directions.
|
|
49
|
-
* @param radius - Radius of the scene's visible bounding sphere.
|
|
50
|
-
* @returns The framed radius.
|
|
51
|
-
*/
|
|
52
|
-
function framedRadius(radius: number): number {
|
|
53
|
-
return Math.max(radius * (1 + FRAMING_MARGIN), MIN_FRAMING_RADIUS);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
24
|
/**
|
|
57
25
|
* Frame everything currently in the scene.
|
|
58
26
|
*
|
|
@@ -83,26 +51,6 @@ export function resetCamera(
|
|
|
83
51
|
});
|
|
84
52
|
}
|
|
85
53
|
|
|
86
|
-
/**
|
|
87
|
-
* Turn the automatic spin on or off.
|
|
88
|
-
* @param plugin - The molstar context.
|
|
89
|
-
* @param spinning - Whether the scene should keep turning.
|
|
90
|
-
* @param speed - Turn rate, in molstar's own spin unit.
|
|
91
|
-
*/
|
|
92
|
-
export function setSpin(
|
|
93
|
-
plugin: PluginContext,
|
|
94
|
-
spinning: boolean,
|
|
95
|
-
speed = DEFAULT_SPIN_SPEED,
|
|
96
|
-
): void {
|
|
97
|
-
plugin.canvas3d?.setProps({
|
|
98
|
-
trackball: {
|
|
99
|
-
animate: spinning
|
|
100
|
-
? { name: 'spin', params: { speed, axis: SPIN_AXIS } }
|
|
101
|
-
: { name: 'off', params: {} },
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
54
|
/**
|
|
107
55
|
* Where the camera stands, against the scene rather than its coordinates.
|
|
108
56
|
*
|
|
@@ -121,29 +69,11 @@ export function readCamera(plugin: PluginContext): Molecule3DCamera | null {
|
|
|
121
69
|
if (!(radius > 0)) return null;
|
|
122
70
|
const framed = framedRadius(radius);
|
|
123
71
|
const camera = canvas.camera;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// The trackball keeps up and back close to square, never exactly so.
|
|
130
|
-
const trueUp = Vec3.scaleAndAdd(Vec3.zero(), up, back, -Vec3.dot(up, back));
|
|
131
|
-
if (Vec3.magnitude(trueUp) <= 0) return null;
|
|
132
|
-
Vec3.normalize(trueUp, trueUp);
|
|
133
|
-
const right = Vec3.cross(Vec3.zero(), trueUp, back);
|
|
134
|
-
const rotation = Quat.fromBasis(Quat.identity(), right, trueUp, back);
|
|
135
|
-
const offset = Vec3.sub(Vec3.zero(), target, center);
|
|
136
|
-
Vec3.scale(offset, offset, 1 / framed);
|
|
137
|
-
return normalizeMolecule3DCamera({
|
|
138
|
-
rotation: [
|
|
139
|
-
rotation[0] ?? 0,
|
|
140
|
-
rotation[1] ?? 0,
|
|
141
|
-
rotation[2] ?? 0,
|
|
142
|
-
rotation[3] ?? 1,
|
|
143
|
-
],
|
|
144
|
-
zoom: camera.getTargetDistance(framed) / distance,
|
|
145
|
-
offset: [offset[0] ?? 0, offset[1] ?? 0, offset[2] ?? 0],
|
|
146
|
-
});
|
|
72
|
+
return poseToCamera(
|
|
73
|
+
camera.getSnapshot(),
|
|
74
|
+
{ center, radius: framed },
|
|
75
|
+
camera.getTargetDistance(framed),
|
|
76
|
+
);
|
|
147
77
|
}
|
|
148
78
|
|
|
149
79
|
/**
|
|
@@ -161,23 +91,18 @@ export function applyCamera(
|
|
|
161
91
|
camera: Molecule3DCamera,
|
|
162
92
|
durationMilliseconds = 0,
|
|
163
93
|
): void {
|
|
164
|
-
const { rotation, zoom, offset } = normalizeMolecule3DCamera(camera);
|
|
165
|
-
const turn = Quat.create(rotation[0], rotation[1], rotation[2], rotation[3]);
|
|
166
94
|
plugin.canvas3d?.requestCameraReset({
|
|
167
95
|
durationMs: durationMilliseconds,
|
|
168
96
|
snapshot: (scene, current) => {
|
|
169
97
|
const { center, radius } = scene.boundingSphereVisible;
|
|
170
98
|
const framed = framedRadius(radius);
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
(
|
|
176
|
-
(center[2] ?? 0) + offset[2] * framed,
|
|
99
|
+
const reference = { center, radius: framed };
|
|
100
|
+
const pose = cameraToPose(
|
|
101
|
+
camera,
|
|
102
|
+
reference,
|
|
103
|
+
current.getTargetDistance(framed),
|
|
177
104
|
);
|
|
178
|
-
|
|
179
|
-
const position = Vec3.scaleAndAdd(Vec3.zero(), target, back, distance);
|
|
180
|
-
return { target, position, up, radius: framed };
|
|
105
|
+
return { ...pose, radius: framed };
|
|
181
106
|
},
|
|
182
107
|
});
|
|
183
108
|
}
|
|
@@ -7,7 +7,11 @@ import { sanitizeFileName } from '../../download/core/sanitizeFileName.ts';
|
|
|
7
7
|
import type { ImageSize } from '../core/exportImage.ts';
|
|
8
8
|
import { dataUriBytes, rasterSvgMarkup } from '../core/exportImage.ts';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/** The one thing an export asks of a viewer: a picture of its scene. */
|
|
11
|
+
export interface SceneCapture {
|
|
12
|
+
/** Render the scene at that pixel size, as a `data:` URI. */
|
|
13
|
+
captureImage: (size: ImageSize) => Promise<string | undefined>;
|
|
14
|
+
}
|
|
11
15
|
|
|
12
16
|
/** What {@link exportMoleculeImage} writes. */
|
|
13
17
|
export interface MoleculeImageRequest {
|
|
@@ -27,7 +31,7 @@ export interface MoleculeImageRequest {
|
|
|
27
31
|
* @returns Nothing; resolves once the download has been started.
|
|
28
32
|
*/
|
|
29
33
|
export async function exportMoleculeImage(
|
|
30
|
-
viewer:
|
|
34
|
+
viewer: SceneCapture,
|
|
31
35
|
request: MoleculeImageRequest,
|
|
32
36
|
): Promise<void> {
|
|
33
37
|
const { format, scale, size, fileName } = request;
|
|
@@ -7,5 +7,17 @@
|
|
|
7
7
|
* erased and so are safe.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
export { Molecule3DExport } from './Molecule3DExport.tsx';
|
|
11
|
+
export type { Molecule3DExportProps } from './Molecule3DExport.tsx';
|
|
12
|
+
export { Molecule3DHelp } from './Molecule3DHelp.tsx';
|
|
13
|
+
export { Molecule3DToolbar } from './Molecule3DToolbar.tsx';
|
|
14
|
+
export type { Molecule3DToolbarProps } from './Molecule3DToolbar.tsx';
|
|
15
|
+
export type {
|
|
16
|
+
MoleculeImageRequest,
|
|
17
|
+
SceneCapture,
|
|
18
|
+
} from './exportMoleculeImage.ts';
|
|
19
|
+
export { exportMoleculeImage } from './exportMoleculeImage.ts';
|
|
20
|
+
export type { ImageExport } from './useImageExport.ts';
|
|
21
|
+
export { useImageExport } from './useImageExport.ts';
|
|
10
22
|
export { MoleculeViewer3D } from './MoleculeViewer3D.tsx';
|
|
11
23
|
export type { MoleculeViewer3DProps } from './moleculeViewer3DProps.ts';
|