react-cheminfo 0.18.0 → 0.19.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.
Files changed (108) hide show
  1. package/lib/about/core/about.d.ts +9 -0
  2. package/lib/about/core/about.d.ts.map +1 -1
  3. package/lib/about/core/about.js +1 -0
  4. package/lib/about/core/about.js.map +1 -1
  5. package/lib/about/core/index.d.ts +1 -0
  6. package/lib/about/core/index.d.ts.map +1 -1
  7. package/lib/about/core/index.js +1 -0
  8. package/lib/about/core/index.js.map +1 -1
  9. package/lib/about/core/repository.d.ts +14 -0
  10. package/lib/about/core/repository.d.ts.map +1 -0
  11. package/lib/about/core/repository.js +21 -0
  12. package/lib/about/core/repository.js.map +1 -0
  13. package/lib/about/ui/AboutBuild.d.ts +5 -4
  14. package/lib/about/ui/AboutBuild.d.ts.map +1 -1
  15. package/lib/about/ui/AboutBuild.js +10 -10
  16. package/lib/about/ui/AboutBuild.js.map +1 -1
  17. package/lib/about/ui/AboutPage.d.ts.map +1 -1
  18. package/lib/about/ui/AboutPage.js +7 -8
  19. package/lib/about/ui/AboutPage.js.map +1 -1
  20. package/lib/about/ui/AboutVersion.d.ts +25 -0
  21. package/lib/about/ui/AboutVersion.d.ts.map +1 -0
  22. package/lib/about/ui/AboutVersion.js +31 -0
  23. package/lib/about/ui/AboutVersion.js.map +1 -0
  24. package/lib/about/ui/index.d.ts +2 -0
  25. package/lib/about/ui/index.d.ts.map +1 -1
  26. package/lib/about/ui/index.js +1 -0
  27. package/lib/about/ui/index.js.map +1 -1
  28. package/lib/build/core/buildInfo.d.ts +16 -0
  29. package/lib/build/core/buildInfo.d.ts.map +1 -1
  30. package/lib/build/core/buildInfo.js +21 -0
  31. package/lib/build/core/buildInfo.js.map +1 -1
  32. package/lib/build/core/index.d.ts +1 -1
  33. package/lib/build/core/index.d.ts.map +1 -1
  34. package/lib/build/core/index.js +1 -1
  35. package/lib/build/core/index.js.map +1 -1
  36. package/lib/build/vite/buildInfo.d.ts.map +1 -1
  37. package/lib/build/vite/buildInfo.js +2 -2
  38. package/lib/build/vite/buildInfo.js.map +1 -1
  39. package/lib/ecosystem/core/sites.d.ts.map +1 -1
  40. package/lib/ecosystem/core/sites.js +12 -0
  41. package/lib/ecosystem/core/sites.js.map +1 -1
  42. package/lib/ecosystem/core/types.d.ts +8 -0
  43. package/lib/ecosystem/core/types.d.ts.map +1 -1
  44. package/lib/molecule3d/core/camera.d.ts +89 -0
  45. package/lib/molecule3d/core/camera.d.ts.map +1 -0
  46. package/lib/molecule3d/core/camera.js +172 -0
  47. package/lib/molecule3d/core/camera.js.map +1 -0
  48. package/lib/molecule3d/core/index.d.ts +2 -0
  49. package/lib/molecule3d/core/index.d.ts.map +1 -1
  50. package/lib/molecule3d/core/index.js +1 -0
  51. package/lib/molecule3d/core/index.js.map +1 -1
  52. package/lib/molecule3d/ui/MoleculeCanvas3D.d.ts.map +1 -1
  53. package/lib/molecule3d/ui/MoleculeCanvas3D.js +14 -37
  54. package/lib/molecule3d/ui/MoleculeCanvas3D.js.map +1 -1
  55. package/lib/molecule3d/ui/camera.d.ts +35 -2
  56. package/lib/molecule3d/ui/camera.d.ts.map +1 -1
  57. package/lib/molecule3d/ui/camera.js +113 -4
  58. package/lib/molecule3d/ui/camera.js.map +1 -1
  59. package/lib/molecule3d/ui/captureScene.d.ts +14 -0
  60. package/lib/molecule3d/ui/captureScene.d.ts.map +1 -0
  61. package/lib/molecule3d/ui/captureScene.js +24 -0
  62. package/lib/molecule3d/ui/captureScene.js.map +1 -0
  63. package/lib/molecule3d/ui/createViewer.d.ts +18 -0
  64. package/lib/molecule3d/ui/createViewer.d.ts.map +1 -0
  65. package/lib/molecule3d/ui/createViewer.js +19 -0
  66. package/lib/molecule3d/ui/createViewer.js.map +1 -0
  67. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts +21 -0
  68. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts.map +1 -1
  69. package/lib/molecule3d/ui/useMoleculeScene.d.ts +47 -0
  70. package/lib/molecule3d/ui/useMoleculeScene.d.ts.map +1 -0
  71. package/lib/molecule3d/ui/useMoleculeScene.js +82 -0
  72. package/lib/molecule3d/ui/useMoleculeScene.js.map +1 -0
  73. package/lib/molecule3d/ui/useSharedCamera.d.ts +52 -0
  74. package/lib/molecule3d/ui/useSharedCamera.d.ts.map +1 -0
  75. package/lib/molecule3d/ui/useSharedCamera.js +82 -0
  76. package/lib/molecule3d/ui/useSharedCamera.js.map +1 -0
  77. package/lib/molecule3d/ui/viewer.d.ts +21 -15
  78. package/lib/molecule3d/ui/viewer.d.ts.map +1 -1
  79. package/lib/molecule3d/ui/viewer.js +41 -47
  80. package/lib/molecule3d/ui/viewer.js.map +1 -1
  81. package/lib/molecule3d/ui/viewerSpec.d.ts +17 -0
  82. package/lib/molecule3d/ui/viewerSpec.d.ts.map +1 -0
  83. package/lib/molecule3d/ui/viewerSpec.js +34 -0
  84. package/lib/molecule3d/ui/viewerSpec.js.map +1 -0
  85. package/package.json +1 -1
  86. package/src/about/core/about.ts +11 -0
  87. package/src/about/core/index.ts +1 -0
  88. package/src/about/core/repository.ts +22 -0
  89. package/src/about/ui/AboutBuild.tsx +13 -20
  90. package/src/about/ui/AboutPage.tsx +30 -22
  91. package/src/about/ui/AboutVersion.tsx +67 -0
  92. package/src/about/ui/index.ts +2 -0
  93. package/src/build/core/buildInfo.ts +24 -0
  94. package/src/build/core/index.ts +6 -1
  95. package/src/build/vite/buildInfo.ts +2 -2
  96. package/src/ecosystem/core/sites.ts +12 -0
  97. package/src/ecosystem/core/types.ts +8 -0
  98. package/src/molecule3d/core/camera.ts +212 -0
  99. package/src/molecule3d/core/index.ts +14 -0
  100. package/src/molecule3d/ui/MoleculeCanvas3D.tsx +14 -43
  101. package/src/molecule3d/ui/camera.ts +128 -7
  102. package/src/molecule3d/ui/captureScene.ts +31 -0
  103. package/src/molecule3d/ui/createViewer.ts +24 -0
  104. package/src/molecule3d/ui/moleculeViewer3DProps.ts +21 -0
  105. package/src/molecule3d/ui/useMoleculeScene.ts +141 -0
  106. package/src/molecule3d/ui/useSharedCamera.ts +121 -0
  107. package/src/molecule3d/ui/viewer.ts +45 -50
  108. package/src/molecule3d/ui/viewerSpec.ts +38 -0
@@ -1,8 +1,11 @@
1
1
  /**
2
- * The two camera moves the molecule viewer needs: frame whatever is on screen,
3
- * and the slow spin that makes a still picture of a 3D molecule readable.
2
+ * The camera moves the molecule viewer needs: frame whatever is on screen, the
3
+ * slow spin that makes a still picture of a 3D molecule readable, and the two
4
+ * directions between molstar's camera and the scene-relative camera a link
5
+ * carries.
4
6
  */
5
- import { Vec3 } from 'molstar/lib/mol-math/linear-algebra.js';
7
+ import { Quat, Vec3 } from 'molstar/lib/mol-math/linear-algebra.js';
8
+ import { normalizeMolecule3DCamera } from "../core/camera.js";
6
9
  /** Transition length used when the caller does not pick one, milliseconds. */
7
10
  export const DEFAULT_CAMERA_DURATION = 250;
8
11
  /** Turn rate used when the caller does not pick one, in molstar's spin unit. */
@@ -23,6 +26,19 @@ const MIN_FRAMING_RADIUS = 0.5;
23
26
  /** Screen up and viewing direction when the model is seen as its file lays it. */
24
27
  const FRONT_UP = Vec3.create(0, 1, 0);
25
28
  const FRONT_DIRECTION = Vec3.create(0, 0, -1);
29
+ /** The camera's own axes, which the stored rotation turns into world ones. */
30
+ const CAMERA_UP = Vec3.create(0, 1, 0);
31
+ const CAMERA_BACK = Vec3.create(0, 0, 1);
32
+ /**
33
+ * The radius a reset frames, which is the length every stored camera is
34
+ * measured against — so reading a camera and applying it are the same move in
35
+ * opposite directions.
36
+ * @param radius - Radius of the scene's visible bounding sphere.
37
+ * @returns The framed radius.
38
+ */
39
+ function framedRadius(radius) {
40
+ return Math.max(radius * (1 + FRAMING_MARGIN), MIN_FRAMING_RADIUS);
41
+ }
26
42
  /**
27
43
  * Frame everything currently in the scene.
28
44
  *
@@ -41,7 +57,7 @@ export function resetCamera(plugin, durationMilliseconds = DEFAULT_CAMERA_DURATI
41
57
  durationMs: durationMilliseconds,
42
58
  snapshot: (scene, camera) => {
43
59
  const { center, radius } = scene.boundingSphereVisible;
44
- const framed = Math.max(radius * (1 + FRAMING_MARGIN), MIN_FRAMING_RADIUS);
60
+ const framed = framedRadius(radius);
45
61
  return fromFront
46
62
  ? camera.getFocus(center, framed, FRONT_UP, FRONT_DIRECTION)
47
63
  : camera.getFocus(center, framed);
@@ -63,4 +79,97 @@ export function setSpin(plugin, spinning, speed = DEFAULT_SPIN_SPEED) {
63
79
  },
64
80
  });
65
81
  }
82
+ /**
83
+ * Where the camera stands, against the scene rather than its coordinates.
84
+ *
85
+ * An empty scene has no camera to read: a canvas showing nothing still has one,
86
+ * pointing at the origin from molstar's default distance, and measuring that
87
+ * against a sphere of no radius describes a view that means nothing — which
88
+ * would then be applied to the first molecule drawn.
89
+ * @param plugin - The molstar context.
90
+ * @returns The camera, or `null` when there is no canvas or nothing to measure
91
+ * it against.
92
+ */
93
+ export function readCamera(plugin) {
94
+ const canvas = plugin.canvas3d;
95
+ if (canvas === undefined)
96
+ return null;
97
+ const { center, radius } = canvas.boundingSphereVisible;
98
+ if (!(radius > 0))
99
+ return null;
100
+ const framed = framedRadius(radius);
101
+ const camera = canvas.camera;
102
+ const { position, target, up } = camera.getSnapshot();
103
+ const back = Vec3.sub(Vec3.zero(), position, target);
104
+ const distance = Vec3.magnitude(back);
105
+ if (distance <= 0)
106
+ return null;
107
+ Vec3.scale(back, back, 1 / distance);
108
+ // The trackball keeps up and back close to square, never exactly so.
109
+ const trueUp = Vec3.scaleAndAdd(Vec3.zero(), up, back, -Vec3.dot(up, back));
110
+ if (Vec3.magnitude(trueUp) <= 0)
111
+ return null;
112
+ Vec3.normalize(trueUp, trueUp);
113
+ const right = Vec3.cross(Vec3.zero(), trueUp, back);
114
+ const rotation = Quat.fromBasis(Quat.identity(), right, trueUp, back);
115
+ const offset = Vec3.sub(Vec3.zero(), target, center);
116
+ Vec3.scale(offset, offset, 1 / framed);
117
+ return normalizeMolecule3DCamera({
118
+ rotation: [
119
+ rotation[0] ?? 0,
120
+ rotation[1] ?? 0,
121
+ rotation[2] ?? 0,
122
+ rotation[3] ?? 1,
123
+ ],
124
+ zoom: camera.getTargetDistance(framed) / distance,
125
+ offset: [offset[0] ?? 0, offset[1] ?? 0, offset[2] ?? 0],
126
+ });
127
+ }
128
+ /**
129
+ * Put the camera back where a link says it stood.
130
+ *
131
+ * Ordered through `requestCameraReset` for the same reason {@link resetCamera}
132
+ * is: the bounding sphere the camera is measured against is only refreshed when
133
+ * the canvas commits the scene, so the move is computed then rather than now.
134
+ * @param plugin - The molstar context.
135
+ * @param camera - Where to stand.
136
+ * @param durationMilliseconds - Transition length. Pass 0 for an instant jump.
137
+ */
138
+ export function applyCamera(plugin, camera, durationMilliseconds = 0) {
139
+ const { rotation, zoom, offset } = normalizeMolecule3DCamera(camera);
140
+ const turn = Quat.create(rotation[0], rotation[1], rotation[2], rotation[3]);
141
+ plugin.canvas3d?.requestCameraReset({
142
+ durationMs: durationMilliseconds,
143
+ snapshot: (scene, current) => {
144
+ const { center, radius } = scene.boundingSphereVisible;
145
+ const framed = framedRadius(radius);
146
+ const up = Vec3.transformQuat(Vec3.zero(), CAMERA_UP, turn);
147
+ const back = Vec3.transformQuat(Vec3.zero(), CAMERA_BACK, turn);
148
+ const target = Vec3.create((center[0] ?? 0) + offset[0] * framed, (center[1] ?? 0) + offset[1] * framed, (center[2] ?? 0) + offset[2] * framed);
149
+ const distance = current.getTargetDistance(framed) / zoom;
150
+ const position = Vec3.scaleAndAdd(Vec3.zero(), target, back, distance);
151
+ return { target, position, up, radius: framed };
152
+ },
153
+ });
154
+ }
155
+ /**
156
+ * Follow the camera, however it moves — a drag, the reset button, the spin.
157
+ * @param plugin - The molstar context.
158
+ * @param listener - Called after every move, with the camera it left.
159
+ * @returns A function that stops calling the listener.
160
+ */
161
+ export function watchCamera(plugin, listener) {
162
+ const camera = plugin.canvas3d?.camera;
163
+ if (camera === undefined)
164
+ return noop;
165
+ const subscription = camera.changed.subscribe(() => {
166
+ listener(readCamera(plugin));
167
+ });
168
+ return () => {
169
+ subscription.unsubscribe();
170
+ };
171
+ }
172
+ function noop() {
173
+ // Nothing was subscribed, so there is nothing to unsubscribe.
174
+ }
66
175
  //# sourceMappingURL=camera.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"camera.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/camera.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,wCAAwC,CAAC;AAG9D,8EAA8E;AAC9E,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C,gFAAgF;AAChF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAG,CAAC,CAAC;AAExC;;;;;;;GAOG;AACH,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,sDAAsD;AACtD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAEvC,+EAA+E;AAC/E,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B,kFAAkF;AAClF,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACtC,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAE9C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CACzB,MAAqB,EACrB,oBAAoB,GAAG,uBAAuB,EAC9C,SAAS,GAAG,KAAK;IAEjB,MAAM,CAAC,QAAQ,EAAE,kBAAkB,CAAC;QAClC,UAAU,EAAE,oBAAoB;QAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAC1B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,qBAAqB,CAAC;YACvD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CACrB,MAAM,GAAG,CAAC,CAAC,GAAG,cAAc,CAAC,EAC7B,kBAAkB,CACnB,CAAC;YACF,OAAO,SAAS;gBACd,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,CAAC;gBAC5D,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CACrB,MAAqB,EACrB,QAAiB,EACjB,KAAK,GAAG,kBAAkB;IAE1B,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;QACxB,SAAS,EAAE;YACT,OAAO,EAAE,QAAQ;gBACf,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;gBACtD,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;SAChC;KACF,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"camera.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/camera.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A picture of the scene, rendered off screen at a size of its own.
3
+ */
4
+ import type { PluginContext } from 'molstar/lib/mol-plugin/context.js';
5
+ import type { ImageSize } from '../core/exportImage.ts';
6
+ /**
7
+ * Render the scene without its selection highlights or its axes.
8
+ * @param plugin - The molstar context.
9
+ * @param size - Pixel size of the picture.
10
+ * @returns The PNG as a data URI.
11
+ * @throws {Error} When the plugin has no screenshot helper.
12
+ */
13
+ export declare function captureScene(plugin: PluginContext, size: ImageSize): Promise<string>;
14
+ //# sourceMappingURL=captureScene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captureScene.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/captureScene.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,CAYjB"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * A picture of the scene, rendered off screen at a size of its own.
3
+ */
4
+ /**
5
+ * Render the scene without its selection highlights or its axes.
6
+ * @param plugin - The molstar context.
7
+ * @param size - Pixel size of the picture.
8
+ * @returns The PNG as a data URI.
9
+ * @throws {Error} When the plugin has no screenshot helper.
10
+ */
11
+ export async function captureScene(plugin, size) {
12
+ const helper = plugin.helpers.viewportScreenshot;
13
+ if (helper === undefined) {
14
+ throw new Error('This viewer cannot take a picture of its scene.');
15
+ }
16
+ helper.behaviors.values.next({
17
+ ...helper.values,
18
+ resolution: { name: 'custom', params: size },
19
+ axes: { name: 'off', params: {} },
20
+ transparent: false,
21
+ });
22
+ return helper.getImageDataUri();
23
+ }
24
+ //# sourceMappingURL=captureScene.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captureScene.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/captureScene.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAqB,EACrB,IAAe;IAEf,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC;IACjD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;QAC3B,GAAG,MAAM,CAAC,MAAM;QAChB,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE;QAC5C,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;QACjC,WAAW,EAAE,KAAK;KACnB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,eAAe,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * How a molecule viewer comes into being, and why it does so synchronously.
3
+ *
4
+ * React 19 runs an effect, its cleanup and the effect again on every mount in
5
+ * development, so an awaited constructor hands the cleanup nothing to dispose
6
+ * and leaks a WebGL context per mount. Returning the handle immediately means
7
+ * `dispose()` can always be called; the work is queued behind `ready`.
8
+ */
9
+ import { Molecule3DViewer } from './viewer.ts';
10
+ import type { Molecule3DViewerOptions } from './viewerTypes.ts';
11
+ /**
12
+ * Create a viewer inside `container` and start initialising it.
13
+ * @param container - A positioned element; molstar inserts its canvas into it.
14
+ * @param options - See {@link Molecule3DViewerOptions}.
15
+ * @returns A handle that is safe to dispose immediately.
16
+ */
17
+ export declare function createMolecule3DViewer(container: HTMLElement, options?: Molecule3DViewerOptions): Molecule3DViewer;
18
+ //# sourceMappingURL=createViewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createViewer.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/createViewer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAEhE;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,WAAW,EACtB,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAElB"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * How a molecule viewer comes into being, and why it does so synchronously.
3
+ *
4
+ * React 19 runs an effect, its cleanup and the effect again on every mount in
5
+ * development, so an awaited constructor hands the cleanup nothing to dispose
6
+ * and leaks a WebGL context per mount. Returning the handle immediately means
7
+ * `dispose()` can always be called; the work is queued behind `ready`.
8
+ */
9
+ import { Molecule3DViewer } from "./viewer.js";
10
+ /**
11
+ * Create a viewer inside `container` and start initialising it.
12
+ * @param container - A positioned element; molstar inserts its canvas into it.
13
+ * @param options - See {@link Molecule3DViewerOptions}.
14
+ * @returns A handle that is safe to dispose immediately.
15
+ */
16
+ export function createMolecule3DViewer(container, options = {}) {
17
+ return new Molecule3DViewer(container, options);
18
+ }
19
+ //# sourceMappingURL=createViewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createViewer.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/createViewer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,SAAsB,EACtB,UAAmC,EAAE;IAErC,OAAO,IAAI,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAClD,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { ViewerCapability } from '../../orbital/ui/capability.ts';
3
+ import type { Molecule3DCamera } from '../core/camera.ts';
3
4
  import type { Measurement } from '../core/measurement.ts';
4
5
  import type { Molecule3DFile, Molecule3DSettings, Molecule3DTools } from '../core/settings.ts';
5
6
  /**
@@ -72,6 +73,26 @@ export interface MoleculeViewer3DProps {
72
73
  * @default undefined
73
74
  */
74
75
  onMeasurementsChange?: (measurements: readonly Measurement[]) => void;
76
+ /**
77
+ * Where the camera stands when the first molecule is framed — what a shared
78
+ * link carries. The camera belongs to whoever is dragging it afterwards, so
79
+ * this is read once and a later change is ignored; the viewer reports every
80
+ * move through `onCameraChange` instead.
81
+ * @default null — the molecule is framed as `frameNewMolecule` says
82
+ */
83
+ initialCamera?: Molecule3DCamera | null;
84
+ /**
85
+ * Called once the camera has come to rest, with where it stands. Not called
86
+ * while the model is spinning: a spinning camera has no orientation to keep.
87
+ * @default undefined
88
+ */
89
+ onCameraChange?: (camera: Molecule3DCamera) => void;
90
+ /**
91
+ * How long the camera must be still before `onCameraChange` is called,
92
+ * milliseconds, so one drag is one report rather than one per frame.
93
+ * @default 400
94
+ */
95
+ cameraSettleDelay?: number;
75
96
  /**
76
97
  * Name of an exported image, without its extension.
77
98
  * @default 'molecule'
@@ -1 +1 @@
1
- {"version":3,"file":"moleculeViewer3DProps.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/moleculeViewer3DProps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC9C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC1D;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IACtC;;;OAGG;IACH,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,KAAK,IAAI,CAAC;IACtE;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,SAAS,CAAC;CACjE"}
1
+ {"version":3,"file":"moleculeViewer3DProps.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/moleculeViewer3DProps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC9C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC1D;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IACtC;;;OAGG;IACH,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,KAAK,IAAI,CAAC;IACtE;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxC;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpD;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,SAAS,CAAC;CACjE"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Keeping one molstar canvas showing what the props describe: the model, its
3
+ * surface, its measurements, and where the camera stands over them.
4
+ *
5
+ * The draw is coalesced into one animation frame, so dragging a slider costs
6
+ * one rebuild rather than one per pixel, and the camera is framed only when the
7
+ * molecule is new — a restyle that snapped the view back would undo the
8
+ * reader's orientation.
9
+ */
10
+ import type { RefObject } from 'react';
11
+ import type { Measurement } from '../core/measurement.ts';
12
+ import type { Molecule3DFile, Molecule3DSettings } from '../core/settings.ts';
13
+ import type { MoleculeViewer3DProps } from './moleculeViewer3DProps.ts';
14
+ import type { Molecule3DViewer } from './viewer.ts';
15
+ /** What {@link useMoleculeScene} is given. */
16
+ export interface MoleculeSceneOptions {
17
+ /** The element molstar draws in, or `null` before it exists. */
18
+ container: HTMLElement | null;
19
+ /** The viewer mounted in it. */
20
+ viewerRef: RefObject<Molecule3DViewer | null>;
21
+ /** What to draw, or `null` to empty the scene. */
22
+ molfile: Molecule3DFile | null;
23
+ /** How the camera meets a molecule it has not seen before. */
24
+ frameNewMolecule: 'front' | 'keep';
25
+ /** How the model is drawn. */
26
+ settings: Molecule3DSettings;
27
+ /** What is drawn over it. */
28
+ measurements: readonly Measurement[];
29
+ /** Whether the model is turning on its own. */
30
+ spinning: boolean;
31
+ /** Called with a drawing failure, and with `null` once a draw succeeds. */
32
+ onFailureChange: (message: string | null) => void;
33
+ /** Where the camera stands when the first molecule is framed, and who to tell. */
34
+ camera: Pick<MoleculeViewer3DProps, 'cameraSettleDelay' | 'initialCamera' | 'onCameraChange'>;
35
+ }
36
+ /** What {@link useMoleculeScene} answers. */
37
+ export interface MoleculeScene {
38
+ /** Frame everything on screen again, as the toolbar's reset button does. */
39
+ resetView: () => void;
40
+ }
41
+ /**
42
+ * Draw the scene the options describe, and keep it drawn.
43
+ * @param options - See {@link MoleculeSceneOptions}.
44
+ * @returns See {@link MoleculeScene}.
45
+ */
46
+ export declare function useMoleculeScene(options: MoleculeSceneOptions): MoleculeScene;
47
+ //# sourceMappingURL=useMoleculeScene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMoleculeScene.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/useMoleculeScene.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG9E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAKxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,gCAAgC;IAChC,SAAS,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC9C,kDAAkD;IAClD,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,8DAA8D;IAC9D,gBAAgB,EAAE,OAAO,GAAG,MAAM,CAAC;IACnC,8BAA8B;IAC9B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,6BAA6B;IAC7B,YAAY,EAAE,SAAS,WAAW,EAAE,CAAC;IACrC,+CAA+C;IAC/C,QAAQ,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD,kFAAkF;IAClF,MAAM,EAAE,IAAI,CACV,qBAAqB,EACrB,mBAAmB,GAAG,eAAe,GAAG,gBAAgB,CACzD,CAAC;CACH;AAED,6CAA6C;AAC7C,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA+E7E"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Keeping one molstar canvas showing what the props describe: the model, its
3
+ * surface, its measurements, and where the camera stands over them.
4
+ *
5
+ * The draw is coalesced into one animation frame, so dragging a slider costs
6
+ * one rebuild rather than one per pixel, and the camera is framed only when the
7
+ * molecule is new — a restyle that snapped the view back would undo the
8
+ * reader's orientation.
9
+ */
10
+ import { useCallback, useEffect, useRef } from 'react';
11
+ import { drawScene } from "./drawScene.js";
12
+ import { DEFAULT_CAMERA_SETTLE_DELAY, useSharedCamera, } from "./useSharedCamera.js";
13
+ /**
14
+ * Draw the scene the options describe, and keep it drawn.
15
+ * @param options - See {@link MoleculeSceneOptions}.
16
+ * @returns See {@link MoleculeScene}.
17
+ */
18
+ export function useMoleculeScene(options) {
19
+ const { container, viewerRef, molfile, frameNewMolecule, settings, measurements, spinning, onFailureChange, camera: cameraProps, } = options;
20
+ const framedRef = useRef(null);
21
+ const reportFailure = useRef(onFailureChange);
22
+ useEffect(() => {
23
+ reportFailure.current = onFailureChange;
24
+ });
25
+ const camera = useSharedCamera({
26
+ container,
27
+ viewerRef,
28
+ spinning,
29
+ initialCamera: cameraProps.initialCamera ?? null,
30
+ onCameraChange: cameraProps.onCameraChange,
31
+ settleDelay: cameraProps.cameraSettleDelay ?? DEFAULT_CAMERA_SETTLE_DELAY,
32
+ });
33
+ useEffect(() => {
34
+ const viewer = viewerRef.current;
35
+ if (container === null || viewer === null)
36
+ return;
37
+ let cancelled = false;
38
+ const frame = requestAnimationFrame(() => {
39
+ const framed = framedRef.current;
40
+ const isNew = molfile !== null &&
41
+ (framed?.molfile !== molfile || framed.viewer !== viewer);
42
+ framedRef.current = molfile === null ? null : { molfile, viewer };
43
+ // The link's camera is spent on the first molecule framed; afterwards the
44
+ // camera is the reader's and a new molecule is framed as usual.
45
+ const linked = isNew
46
+ ? camera.takeLinkedCamera()
47
+ : null;
48
+ const frameCamera = isNew && linked === null ? frameNewMolecule : 'none';
49
+ void drawScene(viewer, molfile, settings, measurements, frameCamera)
50
+ .then(() => {
51
+ if (cancelled)
52
+ return;
53
+ if (linked !== null)
54
+ void viewer.setCamera(linked);
55
+ reportFailure.current(null);
56
+ })
57
+ .catch((error) => {
58
+ if (cancelled)
59
+ return;
60
+ reportFailure.current(error instanceof Error ? error.message : String(error));
61
+ });
62
+ });
63
+ return () => {
64
+ cancelled = true;
65
+ cancelAnimationFrame(frame);
66
+ };
67
+ }, [
68
+ container,
69
+ viewerRef,
70
+ molfile,
71
+ frameNewMolecule,
72
+ settings,
73
+ measurements,
74
+ camera,
75
+ ]);
76
+ const resetView = useCallback(() => {
77
+ camera.noteMove();
78
+ void viewerRef.current?.resetCamera();
79
+ }, [camera, viewerRef]);
80
+ return { resetView };
81
+ }
82
+ //# sourceMappingURL=useMoleculeScene.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMoleculeScene.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/useMoleculeScene.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The camera of the canvas as something a site can keep: the one a link
3
+ * carried, applied to the first molecule framed, and every move the reader
4
+ * makes afterwards, reported once it has come to rest.
5
+ *
6
+ * The camera is never controlled. It belongs to whoever is dragging it, so the
7
+ * site is told where it went rather than asked where it should be — anything
8
+ * else fights the trackball.
9
+ */
10
+ import type { RefObject } from 'react';
11
+ import type { Molecule3DCamera } from '../core/camera.ts';
12
+ import type { Molecule3DViewer } from './viewer.ts';
13
+ /** How long the camera must be still before a move is reported, milliseconds. */
14
+ export declare const DEFAULT_CAMERA_SETTLE_DELAY = 400;
15
+ /** What {@link useSharedCamera} is given. */
16
+ export interface SharedCameraOptions {
17
+ /** The element molstar draws in, or `null` before it exists. */
18
+ container: HTMLElement | null;
19
+ /** The viewer mounted in it. */
20
+ viewerRef: RefObject<Molecule3DViewer | null>;
21
+ /** Where the camera stands when the first molecule is framed. */
22
+ initialCamera: Molecule3DCamera | null;
23
+ /** Called once a move of the reader's has come to rest. */
24
+ onCameraChange?: (camera: Molecule3DCamera) => void;
25
+ /** Whether the model is turning, which suspends reporting. */
26
+ spinning: boolean;
27
+ /** How long the camera must be still before a move is reported. */
28
+ settleDelay: number;
29
+ }
30
+ /**
31
+ * What {@link useSharedCamera} answers. The same object on every render: the
32
+ * draw effect keys on it, and a fresh one would tear the scene down and build
33
+ * it again — which makes molstar frame the model afresh and loses the camera a
34
+ * link had just restored.
35
+ */
36
+ export interface SharedCamera {
37
+ /**
38
+ * The camera a link carried, answered once and then never again — the next
39
+ * molecule is framed the way the viewer frames any other.
40
+ * @returns The camera to stand at, or `null` to frame the molecule.
41
+ */
42
+ takeLinkedCamera: () => Molecule3DCamera | null;
43
+ /** Note a move of the reader's, which is what starts reporting. */
44
+ noteMove: () => void;
45
+ }
46
+ /**
47
+ * Keep the camera of one canvas in step with the site that shows it.
48
+ * @param options - See {@link SharedCameraOptions}.
49
+ * @returns See {@link SharedCamera}.
50
+ */
51
+ export declare function useSharedCamera(options: SharedCameraOptions): SharedCamera;
52
+ //# sourceMappingURL=useSharedCamera.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSharedCamera.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/useSharedCamera.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,iFAAiF;AACjF,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,gCAAgC;IAChC,SAAS,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC9C,iEAAiE;IACjE,aAAa,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACvC,2DAA2D;IAC3D,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpD,8DAA8D;IAC9D,QAAQ,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;IAChD,mEAAmE;IACnE,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CA6D1E"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The camera of the canvas as something a site can keep: the one a link
3
+ * carried, applied to the first molecule framed, and every move the reader
4
+ * makes afterwards, reported once it has come to rest.
5
+ *
6
+ * The camera is never controlled. It belongs to whoever is dragging it, so the
7
+ * site is told where it went rather than asked where it should be — anything
8
+ * else fights the trackball.
9
+ */
10
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
11
+ import { formatMolecule3DCamera } from "../core/camera.js";
12
+ /** How long the camera must be still before a move is reported, milliseconds. */
13
+ export const DEFAULT_CAMERA_SETTLE_DELAY = 400;
14
+ /**
15
+ * Keep the camera of one canvas in step with the site that shows it.
16
+ * @param options - See {@link SharedCameraOptions}.
17
+ * @returns See {@link SharedCamera}.
18
+ */
19
+ export function useSharedCamera(options) {
20
+ const { container, viewerRef, settleDelay } = options;
21
+ // Spent on the first molecule framed.
22
+ const linkedRef = useRef(false);
23
+ // What the last report said, so the settling of a move we ordered ourselves
24
+ // is not handed back to the site as a move the reader made.
25
+ const reportedRef = useRef(null);
26
+ // Whether the reader has touched the canvas, which is what starts reporting.
27
+ const movedRef = useRef(false);
28
+ const latest = useRef(options);
29
+ useEffect(() => {
30
+ latest.current = options;
31
+ });
32
+ const noteMove = useCallback(() => {
33
+ movedRef.current = true;
34
+ }, []);
35
+ const takeLinkedCamera = useCallback(() => {
36
+ if (linkedRef.current)
37
+ return null;
38
+ linkedRef.current = true;
39
+ const camera = latest.current.initialCamera;
40
+ if (camera !== null)
41
+ reportedRef.current = formatMolecule3DCamera(camera);
42
+ return camera;
43
+ }, []);
44
+ // Reporting waits for a first gesture. The camera also drifts on its own — a
45
+ // surface added after the model was framed grows the scene, and the same
46
+ // camera then reads as slightly closer — and a view nobody chose is not one
47
+ // to hand back to the site, let alone to put in a link.
48
+ useEffect(() => {
49
+ const viewer = viewerRef.current;
50
+ if (container === null || viewer === null)
51
+ return;
52
+ let timer = null;
53
+ container.addEventListener('pointerdown', noteMove);
54
+ container.addEventListener('wheel', noteMove, { passive: true });
55
+ const stopWatching = viewer.watchCamera((camera) => {
56
+ if (camera === null)
57
+ return;
58
+ if (timer !== null)
59
+ clearTimeout(timer);
60
+ timer = setTimeout(() => {
61
+ timer = null;
62
+ const current = latest.current;
63
+ if (current.spinning || !movedRef.current)
64
+ return;
65
+ const text = formatMolecule3DCamera(camera);
66
+ if (text === reportedRef.current)
67
+ return;
68
+ reportedRef.current = text;
69
+ current.onCameraChange?.(camera);
70
+ }, settleDelay);
71
+ });
72
+ return () => {
73
+ if (timer !== null)
74
+ clearTimeout(timer);
75
+ container.removeEventListener('pointerdown', noteMove);
76
+ container.removeEventListener('wheel', noteMove);
77
+ stopWatching();
78
+ };
79
+ }, [container, viewerRef, settleDelay, noteMove]);
80
+ return useMemo(() => ({ takeLinkedCamera, noteMove }), [takeLinkedCamera, noteMove]);
81
+ }
82
+ //# sourceMappingURL=useSharedCamera.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSharedCamera.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/useSharedCamera.ts"],"names":[],"mappings":"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"}
@@ -1,25 +1,17 @@
1
1
  /**
2
- * Lifecycle of one molstar molecule viewer.
2
+ * Lifecycle of one molstar molecule viewer: `createMolecule3DViewer` builds
3
+ * one, and every operation a component performs on it is a method here.
3
4
  *
4
- * `createMolecule3DViewer` is **synchronous** on purpose. React 19 runs an
5
- * effect, its cleanup and the effect again on every mount in development, so an
6
- * awaited constructor hands the cleanup nothing to dispose and leaks a WebGL
7
- * context per mount. Returning the handle immediately means `dispose()` can
8
- * always be called; the work is queued behind `ready`.
9
- *
10
- * molstar's own UI is not mounted: every control is the component's.
5
+ * The constructor returns before the canvas exists — see `createViewer.ts` —
6
+ * so every method queues its work behind `ready` and resolves to nothing once
7
+ * the viewer has been disposed. molstar's own UI is not mounted: every control
8
+ * is the component's.
11
9
  */
10
+ import type { Molecule3DCamera } from '../core/camera.ts';
12
11
  import type { ImageSize } from '../core/exportImage.ts';
13
12
  import type { Measurement, MeasurementKind } from '../core/measurement.ts';
14
13
  import type { Molecule3DFile } from '../core/settings.ts';
15
14
  import type { Molecule3DViewerOptions, MoleculeStyle, SurfaceStyle } from './viewerTypes.ts';
16
- /**
17
- * Create a viewer inside `container` and start initialising it.
18
- * @param container - A positioned element; molstar inserts its canvas into it.
19
- * @param options - See {@link Molecule3DViewerOptions}.
20
- * @returns A handle that is safe to dispose immediately.
21
- */
22
- export declare function createMolecule3DViewer(container: HTMLElement, options?: Molecule3DViewerOptions): Molecule3DViewer;
23
15
  /**
24
16
  * One molstar canvas, and every operation the component performs on it. Every
25
17
  * method resolves to nothing once `dispose` has been called.
@@ -85,6 +77,20 @@ export declare class Molecule3DViewer {
85
77
  * @returns Nothing; resolves once the move has been ordered.
86
78
  */
87
79
  resetCamera(durationMilliseconds?: number, fromFront?: boolean): Promise<void>;
80
+ /**
81
+ * Put the camera where a link says it stood.
82
+ * @param camera - Where to stand.
83
+ * @param durationMilliseconds - Transition length; 0 jumps.
84
+ * @returns Nothing; resolves once the move has been ordered.
85
+ */
86
+ setCamera(camera: Molecule3DCamera, durationMilliseconds?: number): Promise<void>;
87
+ /**
88
+ * Follow the camera, however it moves.
89
+ * @param listener - Called after every move.
90
+ * @returns A function that stops calling the listener; safe to call before
91
+ * the canvas exists.
92
+ */
93
+ watchCamera(listener: (camera: Molecule3DCamera | null) => void): () => void;
88
94
  /**
89
95
  * Turn the automatic spin on or off.
90
96
  * @param spinning - Whether the scene should keep turning.