react-cheminfo 0.63.0 → 0.64.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 (48) hide show
  1. package/lib/molecule3d/core/highlight.d.ts +53 -0
  2. package/lib/molecule3d/core/highlight.d.ts.map +1 -0
  3. package/lib/molecule3d/core/highlight.js +102 -0
  4. package/lib/molecule3d/core/highlight.js.map +1 -0
  5. package/lib/molecule3d/core/index.d.ts +2 -0
  6. package/lib/molecule3d/core/index.d.ts.map +1 -1
  7. package/lib/molecule3d/core/index.js +1 -0
  8. package/lib/molecule3d/core/index.js.map +1 -1
  9. package/lib/molecule3d/ui/MoleculeCanvas3D.d.ts.map +1 -1
  10. package/lib/molecule3d/ui/MoleculeCanvas3D.js +7 -1
  11. package/lib/molecule3d/ui/MoleculeCanvas3D.js.map +1 -1
  12. package/lib/molecule3d/ui/highlightColor.d.ts +18 -0
  13. package/lib/molecule3d/ui/highlightColor.d.ts.map +1 -0
  14. package/lib/molecule3d/ui/highlightColor.js +31 -0
  15. package/lib/molecule3d/ui/highlightColor.js.map +1 -0
  16. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts +13 -0
  17. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts.map +1 -1
  18. package/lib/molecule3d/ui/renderMolecule.d.ts +2 -0
  19. package/lib/molecule3d/ui/renderMolecule.d.ts.map +1 -1
  20. package/lib/molecule3d/ui/renderMolecule.js +1 -1
  21. package/lib/molecule3d/ui/renderMolecule.js.map +1 -1
  22. package/lib/molecule3d/ui/viewer.d.ts +9 -0
  23. package/lib/molecule3d/ui/viewer.d.ts.map +1 -1
  24. package/lib/molecule3d/ui/viewer.js +18 -2
  25. package/lib/molecule3d/ui/viewer.js.map +1 -1
  26. package/lib/molstar/core/highlights.d.ts +57 -0
  27. package/lib/molstar/core/highlights.d.ts.map +1 -0
  28. package/lib/molstar/core/highlights.js +178 -0
  29. package/lib/molstar/core/highlights.js.map +1 -0
  30. package/lib/molstar/core/index.d.ts +2 -1
  31. package/lib/molstar/core/index.d.ts.map +1 -1
  32. package/lib/molstar/core/index.js +2 -1
  33. package/lib/molstar/core/index.js.map +1 -1
  34. package/lib/molstar/core/measurements.d.ts +10 -0
  35. package/lib/molstar/core/measurements.d.ts.map +1 -1
  36. package/lib/molstar/core/measurements.js +26 -12
  37. package/lib/molstar/core/measurements.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/molecule3d/core/highlight.ts +133 -0
  40. package/src/molecule3d/core/index.ts +6 -0
  41. package/src/molecule3d/ui/MoleculeCanvas3D.tsx +13 -0
  42. package/src/molecule3d/ui/highlightColor.ts +34 -0
  43. package/src/molecule3d/ui/moleculeViewer3DProps.ts +13 -0
  44. package/src/molecule3d/ui/renderMolecule.ts +1 -1
  45. package/src/molecule3d/ui/viewer.ts +23 -0
  46. package/src/molstar/core/highlights.ts +236 -0
  47. package/src/molstar/core/index.ts +2 -1
  48. package/src/molstar/core/measurements.ts +38 -10
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Atoms and bonds of the displayed molecule emphasised in one colour, for as
3
+ * long as a site keeps pointing at them.
4
+ *
5
+ * Neither of molstar's own markings fits: its hover highlight is erased by the
6
+ * next move of the pointer, and its selection belongs to the measuring tools.
7
+ * This is an overpaint of the model's own representation instead, so it
8
+ * follows the model in every style, survives the hover, and leaves the camera
9
+ * and every other drawing alone.
10
+ *
11
+ * molstar paints an atom and every half-bond leaving it from one element loci,
12
+ * which would tint the C–C bonds of a row that names only C–H ones. So the
13
+ * overpaint has three layers: the atoms, then those half-bonds cleared again,
14
+ * then exactly the bonds the paths name, as bond loci.
15
+ */
16
+ import { OrderedSet, SortedArray } from 'molstar/lib/mol-data/int.js';
17
+ import { Bond, StructureElement, Unit, } from 'molstar/lib/mol-model/structure.js';
18
+ import { PluginStateObject } from 'molstar/lib/mol-plugin-state/objects.js';
19
+ import { Overpaint } from 'molstar/lib/mol-theme/overpaint.js';
20
+ import { highlightedParts, sameHighlights, } from "../../molecule3d/core/highlight.js";
21
+ // Lowercased: they are factories, not constructors.
22
+ const elementLoci = StructureElement.Loci;
23
+ const bondLoci = Bond.Loci;
24
+ const bondLocation = Bond.Location;
25
+ /**
26
+ * The overpaint that emphasises `highlights` on a representation of
27
+ * `structure`: their atoms, and exactly the bonds between consecutive atoms of
28
+ * each path.
29
+ * @param structure - The structure the representation is drawn from.
30
+ * @param highlights - The paths; an atom the structure lacks is skipped.
31
+ * @param color - What they are painted in.
32
+ * @returns The overpaint, empty when no atom is left to paint.
33
+ */
34
+ export function highlightOverpaint(structure, highlights, color) {
35
+ const { atoms, bonds } = highlightedParts(highlights, (atom) => unitOf(structure, atom) !== undefined);
36
+ if (atoms.length === 0)
37
+ return { kind: 'bond-loci', layers: [] };
38
+ const layers = [
39
+ { loci: atomsLoci(structure, atoms), color, clear: false },
40
+ { loci: leavingBondsLoci(structure, atoms), color, clear: true },
41
+ ];
42
+ if (bonds.length > 0) {
43
+ layers.push({ loci: pathBondsLoci(structure, bonds), color, clear: false });
44
+ }
45
+ // Not `element-loci`, which molstar would remap layer by layer as atoms, and
46
+ // a bond loci read as atoms is a crash.
47
+ return { kind: 'bond-loci', layers };
48
+ }
49
+ /**
50
+ * Keeps one representation of the state tree painted with the highlights a
51
+ * site asks for: the one there now, and every one built under the same ref
52
+ * afterwards, so a restyled model or a new conformer comes up already painted.
53
+ */
54
+ export class HighlightPainter {
55
+ #plugin;
56
+ #ref;
57
+ #unsubscribe;
58
+ #highlights = [];
59
+ #color;
60
+ /**
61
+ * Start following the representation at `representationRef`.
62
+ * @param plugin - The molstar context.
63
+ * @param representationRef - State-tree ref of the representation to paint.
64
+ */
65
+ constructor(plugin, representationRef) {
66
+ this.#plugin = plugin;
67
+ this.#ref = representationRef;
68
+ const repaint = (event) => {
69
+ if (event.ref === this.#ref)
70
+ this.#paint(event.obj);
71
+ };
72
+ const { created, updated } = plugin.state.data.events.object;
73
+ const subscriptions = [
74
+ created.subscribe(repaint),
75
+ updated.subscribe(repaint),
76
+ ];
77
+ this.#unsubscribe = () => {
78
+ for (const subscription of subscriptions)
79
+ subscription.unsubscribe();
80
+ };
81
+ }
82
+ /**
83
+ * Paint exactly these highlights, in place of the ones painted.
84
+ * @param highlights - The paths; an empty list restores the plain model.
85
+ * @param color - What they are painted in.
86
+ */
87
+ set(highlights, color) {
88
+ if (color === this.#color && sameHighlights(highlights, this.#highlights)) {
89
+ return;
90
+ }
91
+ this.#highlights = highlights;
92
+ this.#color = color;
93
+ this.#paint(this.#plugin.state.data.cells.get(this.#ref)?.obj);
94
+ }
95
+ /** Stop following the representation. */
96
+ dispose() {
97
+ this.#unsubscribe();
98
+ }
99
+ #paint(object) {
100
+ if (!PluginStateObject.Molecule.Structure.Representation3D.is(object)) {
101
+ return;
102
+ }
103
+ const { repr, sourceData } = object.data;
104
+ const color = this.#color;
105
+ const overpaint = color === undefined
106
+ ? Overpaint.Empty
107
+ : highlightOverpaint(sourceData, this.#highlights, color);
108
+ if (Overpaint.isEmpty(overpaint) &&
109
+ Overpaint.isEmpty(repr.state.overpaint)) {
110
+ return;
111
+ }
112
+ repr.setState({ overpaint });
113
+ // No commit: the scene keeps its bounds, so the camera is never reframed.
114
+ this.#plugin.canvas3d?.update(repr, true);
115
+ }
116
+ }
117
+ function unitOf(structure, atom) {
118
+ const unit = structure.units[atom.unit];
119
+ if (unit === undefined || atom.element >= unit.elements.length) {
120
+ return undefined;
121
+ }
122
+ return unit;
123
+ }
124
+ function atomsLoci(structure, atoms) {
125
+ const elements = [];
126
+ for (let index = 0; index < structure.units.length; index++) {
127
+ const unit = structure.units[index];
128
+ const indices = [];
129
+ for (const atom of atoms) {
130
+ if (atom.unit === index)
131
+ indices.push(atom.element);
132
+ }
133
+ if (unit === undefined || indices.length === 0)
134
+ continue;
135
+ const sorted = SortedArray.ofUnsortedArray(indices);
136
+ elements.push({ unit, indices: OrderedSet.ofSortedArray(sorted) });
137
+ }
138
+ return elementLoci(structure, elements);
139
+ }
140
+ // Every half-bond leaving the atoms, which an element loci paints as well.
141
+ function leavingBondsLoci(structure, atoms) {
142
+ const locations = [];
143
+ const iterator = new Bond.ElementBondIterator();
144
+ for (const atom of atoms) {
145
+ const unit = unitOf(structure, atom);
146
+ if (unit === undefined || !Unit.isAtomic(unit))
147
+ continue;
148
+ const index = atom.element;
149
+ iterator.setElement(structure, unit, index);
150
+ while (iterator.hasNext) {
151
+ const { otherUnit, otherIndex } = iterator.move();
152
+ locations.push(bondLocation(structure, unit, index, structure, otherUnit, otherIndex));
153
+ }
154
+ }
155
+ return bondLoci(structure, locations);
156
+ }
157
+ // molstar draws a bond as two halves, one from each atom.
158
+ function pathBondsLoci(structure, bonds) {
159
+ const locations = [];
160
+ for (const [first, second] of bonds) {
161
+ const forward = halfBond(structure, first, second);
162
+ const backward = halfBond(structure, second, first);
163
+ if (forward !== undefined && backward !== undefined) {
164
+ locations.push(forward, backward);
165
+ }
166
+ }
167
+ return bondLoci(structure, locations);
168
+ }
169
+ function halfBond(structure, from, to) {
170
+ const fromUnit = unitOf(structure, from);
171
+ const toUnit = unitOf(structure, to);
172
+ if (fromUnit === undefined || toUnit === undefined)
173
+ return undefined;
174
+ const fromIndex = from.element;
175
+ const toIndex = to.element;
176
+ return bondLocation(structure, fromUnit, fromIndex, structure, toUnit, toIndex);
177
+ }
178
+ //# sourceMappingURL=highlights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlights.js","sourceRoot":"","sources":["../../../src/molstar/core/highlights.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAGtE,OAAO,EACL,IAAI,EACJ,gBAAgB,EAChB,IAAI,GACL,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAE5E,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAO/D,OAAO,EACL,gBAAgB,EAChB,cAAc,GACf,MAAM,oCAAoC,CAAC;AAG5C,oDAAoD;AACpD,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;AAC3B,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC;AAKnC;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAAoB,EACpB,UAA0C,EAC1C,KAAY;IAEZ,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,gBAAgB,CACvC,UAAU,EACV,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,SAAS,CAChD,CAAC;IACF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACjE,MAAM,MAAM,GAA0C;QACpD,EAAE,IAAI,EAAE,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;QAC1D,EAAE,IAAI,EAAE,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE;KACjE,CAAC;IACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,6EAA6E;IAC7E,wCAAwC;IACxC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,gBAAgB;IAClB,OAAO,CAAgB;IACvB,IAAI,CAAS;IACb,YAAY,CAAa;IAClC,WAAW,GAAmC,EAAE,CAAC;IACjD,MAAM,CAAoB;IAE1B;;;;OAIG;IACH,YAAY,MAAqB,EAAE,iBAAyB;QAC1D,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,MAAM,OAAO,GAAG,CAAC,KAAwC,EAAE,EAAE;YAC3D,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtD,CAAC,CAAC;QACF,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAC7D,MAAM,aAAa,GAAG;YACpB,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC;YAC1B,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC;SAC3B,CAAC;QACF,IAAI,CAAC,YAAY,GAAG,GAAG,EAAE;YACvB,KAAK,MAAM,YAAY,IAAI,aAAa;gBAAE,YAAY,CAAC,WAAW,EAAE,CAAC;QACvE,CAAC,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,UAA0C,EAAE,KAAY;QAC1D,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM,IAAI,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC1E,OAAO;QACT,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACjE,CAAC;IAED,yCAAyC;IACzC,OAAO;QACL,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,MAAM,CAAC,MAA+B;QACpC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;YACtE,OAAO;QACT,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,MAAM,SAAS,GACb,KAAK,KAAK,SAAS;YACjB,CAAC,CAAC,SAAS,CAAC,KAAK;YACjB,CAAC,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC9D,IACE,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;YAC5B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EACvC,CAAC;YACD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QAC7B,0EAA0E;QAC1E,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;CACF;AAED,SAAS,MAAM,CAAC,SAAoB,EAAE,IAAmB;IACvD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC/D,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,SAAS,CAChB,SAAoB,EACpB,KAA+B;IAE/B,MAAM,QAAQ,GAAqD,EAAE,CAAC;IACtE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAC5D,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;gBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACzD,MAAM,MAAM,GAAG,WAAW,CAAC,eAAe,CAAY,OAAO,CAAC,CAAC;QAC/D,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,WAAW,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,2EAA2E;AAC3E,SAAS,gBAAgB,CACvB,SAAoB,EACpB,KAA+B;IAE/B,MAAM,SAAS,GAAoB,EAAE,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;IAChD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAS;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAoB,CAAC;QACxC,QAAQ,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5C,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC;YACxB,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;YAClD,SAAS,CAAC,IAAI,CACZ,YAAY,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CACvE,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AACxC,CAAC;AAED,0DAA0D;AAC1D,SAAS,aAAa,CACpB,SAAoB,EACpB,KAAiC;IAEjC,MAAM,SAAS,GAAoB,EAAE,CAAC;IACtC,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACpD,IAAI,OAAO,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACpD,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,QAAQ,CACf,SAAoB,EACpB,IAAmB,EACnB,EAAiB;IAEjB,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACrC,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACrE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAoB,CAAC;IAC5C,MAAM,OAAO,GAAG,EAAE,CAAC,OAAoB,CAAC;IACxC,OAAO,YAAY,CACjB,SAAS,EACT,QAAQ,EACR,SAAS,EACT,SAAS,EACT,MAAM,EACN,OAAO,CACR,CAAC;AACJ,CAAC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The molstar layer under the 3D views: the plugin lifecycle, the camera, the
3
- * hover labels, the measurements and the picture of a scene.
3
+ * hover labels, the measurements, the highlights and the picture of a scene.
4
4
  *
5
5
  * Three of our sites mount a headless molstar canvas — the molecule viewer
6
6
  * here, lcao's orbitals and symmetry's crystals — and each of them had its own
@@ -17,6 +17,7 @@
17
17
  export type { CameraPose, CameraReference, PoseOptions } from './cameraPose.ts';
18
18
  export { cameraToPose, poseToCamera } from './cameraPose.ts';
19
19
  export { DEFAULT_CAMERA_DURATION, DEFAULT_SPIN_SPEED, FRAMING_MARGIN, MINIMUM_FRAMING_RADIUS, framedRadius, setSpin, } from './camera.ts';
20
+ export { HighlightPainter, highlightOverpaint } from './highlights.ts';
20
21
  export { atomName, atomText, lociText, subscribeHover } from './hover.ts';
21
22
  export type { MolstarPluginOptions } from './plugin.ts';
22
23
  export { MolstarPlugin } from './plugin.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/molstar/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC1E,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/molstar/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC1E,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The molstar layer under the 3D views: the plugin lifecycle, the camera, the
3
- * hover labels, the measurements and the picture of a scene.
3
+ * hover labels, the measurements, the highlights and the picture of a scene.
4
4
  *
5
5
  * Three of our sites mount a headless molstar canvas — the molecule viewer
6
6
  * here, lcao's orbitals and symmetry's crystals — and each of them had its own
@@ -16,6 +16,7 @@
16
16
  */
17
17
  export { cameraToPose, poseToCamera } from "./cameraPose.js";
18
18
  export { DEFAULT_CAMERA_DURATION, DEFAULT_SPIN_SPEED, FRAMING_MARGIN, MINIMUM_FRAMING_RADIUS, framedRadius, setSpin, } from "./camera.js";
19
+ export { HighlightPainter, highlightOverpaint } from "./highlights.js";
19
20
  export { atomName, atomText, lociText, subscribeHover } from "./hover.js";
20
21
  export { MolstarPlugin } from "./plugin.js";
21
22
  export { captureScene } from "./captureScene.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/molstar/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1E,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/molstar/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,OAAO,GACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1E,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC"}
@@ -10,7 +10,9 @@
10
10
  * measurement.
11
11
  */
12
12
  import type { ElementIndex, Structure } from 'molstar/lib/mol-model/structure.js';
13
+ import { StructureElement } from 'molstar/lib/mol-model/structure.js';
13
14
  import type { PluginContext } from 'molstar/lib/mol-plugin/context.js';
15
+ import type { StructureMeasurementManager } from 'molstar/lib/mol-plugin-state/manager/structure/measurement.js';
14
16
  import type { AtomReference, Measurement, MeasurementKind } from '../../molecule3d/core/measurement.ts';
15
17
  /**
16
18
  * Where the atoms a measurement addresses are found in the plugin's state.
@@ -28,6 +30,14 @@ export type MoleculeStructureSource = (plugin: PluginContext) => Structure | und
28
30
  * @returns Nothing; resolves once every label is on screen.
29
31
  */
30
32
  export declare function renderMeasurements(plugin: PluginContext, measurements: readonly Measurement[], structureOf: MoleculeStructureSource): Promise<void>;
33
+ /**
34
+ * Add one measurement to the scene, its label in front of the atoms it names.
35
+ * @param manager - molstar's measurement manager.
36
+ * @param kind - What is measured.
37
+ * @param loci - Its atoms, in order; fewer than the kind needs adds nothing.
38
+ * @returns Nothing; resolves once the measurement is committed.
39
+ */
40
+ export declare function addMeasurement(manager: Pick<StructureMeasurementManager, 'addDistance' | 'addAngle' | 'addDihedral'>, kind: MeasurementKind, loci: readonly StructureElement.Loci[]): Promise<void>;
31
41
  /**
32
42
  * Remove every measurement from the scene.
33
43
  * @param plugin - The molstar context.
@@ -1 +1 @@
1
- {"version":3,"file":"measurements.d.ts","sourceRoot":"","sources":["../../../src/molstar/core/measurements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACV,MAAM,oCAAoC,CAAC;AAE5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAIvE,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,eAAe,EAChB,MAAM,sCAAsC,CAAC;AAM9C;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,aAAa,KAClB,SAAS,GAAG,SAAS,CAAC;AAE3B;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,SAAS,WAAW,EAAE,EACpC,WAAW,EAAE,uBAAuB,GACnC,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5E;AAED,2EAA2E;AAC3E,qBAAa,iBAAiB;;IAO5B;;;;;OAKG;gBAED,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,EAC7C,WAAW,EAAE,uBAAuB;IAmBtC;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI;IAO3C,oCAAoC;IACpC,OAAO,IAAI,IAAI;CAqBhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,YAAY,GACpB,aAAa,GAAG,SAAS,CAS3B"}
1
+ {"version":3,"file":"measurements.d.ts","sourceRoot":"","sources":["../../../src/molstar/core/measurements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACV,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+DAA+D,CAAC;AAIjH,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,eAAe,EAChB,MAAM,sCAAsC,CAAC;AAM9C;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,aAAa,KAClB,SAAS,GAAG,SAAS,CAAC;AAE3B;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,SAAS,WAAW,EAAE,EACpC,WAAW,EAAE,uBAAuB,GACnC,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,IAAI,CACX,2BAA2B,EAC3B,aAAa,GAAG,UAAU,GAAG,aAAa,CAC3C,EACD,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,SAAS,gBAAgB,CAAC,IAAI,EAAE,GACrC,OAAO,CAAC,IAAI,CAAC,CASf;AAQD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5E;AAED,2EAA2E;AAC3E,qBAAa,iBAAiB;;IAO5B;;;;;OAKG;gBAED,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,EAC7C,WAAW,EAAE,uBAAuB;IAmBtC;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI;IAO3C,oCAAoC;IACpC,OAAO,IAAI,IAAI;CAqBhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,YAAY,GACpB,aAAa,GAAG,SAAS,CAS3B"}
@@ -31,20 +31,34 @@ export async function renderMeasurements(plugin, measurements, structureOf) {
31
31
  return;
32
32
  const manager = plugin.managers.structure.measurement;
33
33
  for (const measurement of measurements) {
34
- const [a, b, c, d] = atomLoci(structure, measurement.atoms);
35
- /* eslint-disable no-await-in-loop -- each add commits to the state tree, and commits must not interleave */
36
- if (measurement.kind === 'distance' && a && b) {
37
- await manager.addDistance(a, b);
38
- }
39
- else if (measurement.kind === 'angle' && a && b && c) {
40
- await manager.addAngle(a, b, c);
41
- }
42
- else if (measurement.kind === 'dihedral' && a && b && c && d) {
43
- await manager.addDihedral(a, b, c, d);
44
- }
45
- /* eslint-enable no-await-in-loop */
34
+ // eslint-disable-next-line no-await-in-loop -- each add commits to the state tree, and commits must not interleave
35
+ await addMeasurement(manager, measurement.kind, atomLoci(structure, measurement.atoms));
46
36
  }
47
37
  }
38
+ /**
39
+ * Add one measurement to the scene, its label in front of the atoms it names.
40
+ * @param manager - molstar's measurement manager.
41
+ * @param kind - What is measured.
42
+ * @param loci - Its atoms, in order; fewer than the kind needs adds nothing.
43
+ * @returns Nothing; resolves once the measurement is committed.
44
+ */
45
+ export async function addMeasurement(manager, kind, loci) {
46
+ const [a, b, c, d] = loci;
47
+ if (kind === 'distance' && a && b) {
48
+ await manager.addDistance(a, b, MEASUREMENT_LABEL);
49
+ }
50
+ else if (kind === 'angle' && a && b && c) {
51
+ await manager.addAngle(a, b, c, MEASUREMENT_LABEL);
52
+ }
53
+ else if (kind === 'dihedral' && a && b && c && d) {
54
+ await manager.addDihedral(a, b, c, d, MEASUREMENT_LABEL);
55
+ }
56
+ }
57
+ /**
58
+ * A label drawn at the depth of its atoms hides half behind them: it is drawn
59
+ * in front of them, as molstar's own order labels are.
60
+ */
61
+ const MEASUREMENT_LABEL = { labelParams: { offsetZ: 0.75 } };
48
62
  /**
49
63
  * Remove every measurement from the scene.
50
64
  * @param plugin - The molstar context.
@@ -1 +1 @@
1
- {"version":3,"file":"measurements.js","sourceRoot":"","sources":["../../../src/molstar/core/measurements.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"measurements.js","sourceRoot":"","sources":["../../../src/molstar/core/measurements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAOtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAGtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAOhF,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAE/E,kDAAkD;AAClD,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAY1C;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAqB,EACrB,YAAoC,EACpC,WAAoC;IAEpC,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO;IACpC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,CAAC;IACtD,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,mHAAmH;QACnH,MAAM,cAAc,CAClB,OAAO,EACP,WAAW,CAAC,IAAI,EAChB,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,KAAK,CAAC,CACvC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAGC,EACD,IAAqB,EACrB,IAAsC;IAEtC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;IAC1B,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,iBAAiB,CAAC,CAAC;IACrD,CAAC;SAAM,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,iBAAiB,CAAC,CAAC;IACrD,CAAC;SAAM,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,iBAAiB,GAAG,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;AAE7D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAqB;IAC3D,MAAM,GAAG,GAAG,cAAc,CAAC,gBAAgB,CACzC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EACtB,cAAc,CAAC,OAAO,EACtB,mBAAmB,CACpB,CAAC;IACF,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO;IAC9B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;AAC5C,CAAC;AAED,2EAA2E;AAC3E,MAAM,OAAO,iBAAiB;IACnB,OAAO,CAAgB;IACvB,UAAU,CAAqC;IAC/C,YAAY,CAAa;IACzB,YAAY,CAA0B;IAC/C,KAAK,GAA2B,IAAI,CAAC;IAErC;;;;;OAKG;IACH,YACE,MAAqB,EACrB,SAA6C,EAC7C,WAAoC;QAEpC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,qEAAqE;QACrE,iCAAiC;QACjC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;QACnE,MAAM,YAAY,GAChB,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,uBAAuB,CAAC,SAAS,CAC1E,GAAG,EAAE;YACH,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC,CACF,CAAC;QACJ,IAAI,CAAC,YAAY,GAAG,GAAG,EAAE;YACvB,YAAY,CAAC,WAAW,EAAE,CAAC;QAC7B,CAAC,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,IAA4B;QAClC,IAAI,IAAI,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,OAAO,CAAC,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;QAC3C,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IAChE,CAAC;IAED,oCAAoC;IACpC,OAAO;QACL,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,QAAQ;QACN,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,IAAI,KAAK,IAAI,IAAI,SAAS,KAAK,SAAS;YAAE,OAAO;QACrD,MAAM,MAAM,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;QAC7C,+BAA+B;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,gBAAgB,CAAC;QAC3E,MAAM,KAAK,GAAoB,EAAE,CAAC;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACjE,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,IAAI,GAAG,KAAK,IAAI,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3D,IAAI,IAAI,KAAK,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM;YAAE,OAAO;QAClC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;QAC9D,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAoB,EACpB,OAAqB;IAErB,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;IAC9B,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;QACvC,IAAI,QAAQ,KAAK,SAAS;YAAE,SAAS;QACrC,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrD,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACpD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,aAAa,CACpB,SAAoB,EACpB,IAAU;IAEV,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACtD,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;IAC9B,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QAC/C,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACtC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;QAC/D,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,QAAQ,CACf,SAAoB,EACpB,KAA+B;IAE/B,MAAM,IAAI,GAA4B,EAAE,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAC1E,IAAI,CAAC,IAAI,CACP,WAAW,CAAC,SAAS,EAAE;YACrB,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,OAAoB,CAAC,EAAE;SACrE,CAAC,CACH,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-cheminfo",
3
- "version": "0.63.0",
3
+ "version": "0.64.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",
@@ -0,0 +1,133 @@
1
+ /**
2
+ * What a highlight on a 3D molecule is, without React and without molstar: a
3
+ * bonded path of atoms a site points at — the two atoms of a bond, the three of
4
+ * an angle, the four of a dihedral — for the model to emphasise.
5
+ *
6
+ * Atoms are named by position, as measurements name them, so a row of a table
7
+ * read off one conformer lands on the same atoms of every other conformer of
8
+ * the same molecule.
9
+ */
10
+
11
+ import type { AtomReference } from './measurement.ts';
12
+
13
+ /** One bonded path of atoms to emphasise on the model. */
14
+ export interface Molecule3DHighlight {
15
+ /**
16
+ * The atoms in the order they are bonded: two for a bond, three for the two
17
+ * bonds of an angle, four for the three bonds of a dihedral. One atom
18
+ * emphasises that atom alone.
19
+ */
20
+ atoms: readonly AtomReference[];
21
+ }
22
+
23
+ /** Two consecutive atoms of a path: the bond a highlight emphasises. */
24
+ export type HighlightedBond = readonly [AtomReference, AtomReference];
25
+
26
+ /** Everything a list of highlights emphasises, each atom and bond once. */
27
+ export interface HighlightedParts {
28
+ /** Every atom of every path, in the order the paths first name them. */
29
+ atoms: readonly AtomReference[];
30
+ /** Every pair of consecutive atoms, in the order the paths first name them. */
31
+ bonds: readonly HighlightedBond[];
32
+ }
33
+
34
+ /**
35
+ * The atoms and the bonds a list of highlights emphasises.
36
+ *
37
+ * A bond is a pair of consecutive atoms of one path, and nothing else: two
38
+ * atoms that are both highlighted, but by different paths or not next to each
39
+ * other in one, are not a bond of the highlight — so six C–H paths never
40
+ * emphasise the C–C bond between two of their carbons. An atom the structure
41
+ * lacks is left out, with the two pairs it stands in; the atoms on either side
42
+ * of it are not joined in its place.
43
+ * @param highlights - The paths, as a site passes them.
44
+ * @param hasAtom - Whether the structure on screen has an atom; asked only of
45
+ * references whose two numbers are whole and not negative.
46
+ * @default () => true
47
+ * @returns The atoms and the bonds, each once, in the order first named.
48
+ */
49
+ export function highlightedParts(
50
+ highlights: readonly Molecule3DHighlight[],
51
+ hasAtom: (atom: AtomReference) => boolean = isAnyAtom,
52
+ ): HighlightedParts {
53
+ const atoms: AtomReference[] = [];
54
+ const bonds: HighlightedBond[] = [];
55
+ const atomKeys = new Set<string>();
56
+ const bondKeys = new Set<string>();
57
+ for (const highlight of highlights) {
58
+ let previous: AtomReference | undefined;
59
+ for (const atom of highlight.atoms) {
60
+ const present = isAtomReference(atom) && hasAtom(atom);
61
+ if (present && !atomKeys.has(atomKey(atom))) {
62
+ atomKeys.add(atomKey(atom));
63
+ atoms.push({ unit: atom.unit, element: atom.element });
64
+ }
65
+ if (present && previous !== undefined) {
66
+ const key = bondKey(previous, atom);
67
+ if (key !== null && !bondKeys.has(key)) {
68
+ bondKeys.add(key);
69
+ bonds.push([
70
+ { unit: previous.unit, element: previous.element },
71
+ { unit: atom.unit, element: atom.element },
72
+ ]);
73
+ }
74
+ }
75
+ previous = present ? atom : undefined;
76
+ }
77
+ }
78
+ return { atoms, bonds };
79
+ }
80
+
81
+ /**
82
+ * Whether two lists of highlights name the same atoms, in the same paths and
83
+ * the same order — what decides that the model needs no repainting.
84
+ * @param first - One list.
85
+ * @param second - The other.
86
+ * @returns True when every path of one is the path of the other at its place.
87
+ */
88
+ export function sameHighlights(
89
+ first: readonly Molecule3DHighlight[],
90
+ second: readonly Molecule3DHighlight[],
91
+ ): boolean {
92
+ if (first === second) return true;
93
+ if (first.length !== second.length) return false;
94
+ for (let index = 0; index < first.length; index++) {
95
+ const one = first[index]?.atoms;
96
+ const other = second[index]?.atoms;
97
+ if (one === undefined || other === undefined) return false;
98
+ if (one.length !== other.length) return false;
99
+ for (let position = 0; position < one.length; position++) {
100
+ const atom = one[position];
101
+ const match = other[position];
102
+ if (atom?.unit !== match?.unit || atom?.element !== match?.element) {
103
+ return false;
104
+ }
105
+ }
106
+ }
107
+ return true;
108
+ }
109
+
110
+ function isAnyAtom(): boolean {
111
+ return true;
112
+ }
113
+
114
+ function isAtomReference(atom: AtomReference): boolean {
115
+ return (
116
+ Number.isInteger(atom.unit) &&
117
+ atom.unit >= 0 &&
118
+ Number.isInteger(atom.element) &&
119
+ atom.element >= 0
120
+ );
121
+ }
122
+
123
+ function atomKey(atom: AtomReference): string {
124
+ return `${atom.unit}:${atom.element}`;
125
+ }
126
+
127
+ // One key for a pair whichever way round, and none for an atom with itself.
128
+ function bondKey(first: AtomReference, second: AtomReference): string | null {
129
+ const one = atomKey(first);
130
+ const other = atomKey(second);
131
+ if (one === other) return null;
132
+ return one < other ? `${one}-${other}` : `${other}-${one}`;
133
+ }
@@ -16,6 +16,12 @@ export type { ImageSize } from './exportImage.ts';
16
16
  export { dataUriBytes, rasterSvgMarkup } from './exportImage.ts';
17
17
  export type { Molecule3DGesture, Molecule3DGestureKey } from './gestures.ts';
18
18
  export { MOLECULE_3D_GESTURES } from './gestures.ts';
19
+ export type {
20
+ HighlightedBond,
21
+ HighlightedParts,
22
+ Molecule3DHighlight,
23
+ } from './highlight.ts';
24
+ export { highlightedParts, sameHighlights } from './highlight.ts';
19
25
  export type {
20
26
  AtomReference,
21
27
  Measurement,
@@ -10,6 +10,7 @@ import type { CSSProperties, ReactElement } from 'react';
10
10
  import { useEffect, useRef, useState } from 'react';
11
11
 
12
12
  import { DEFAULT_SPIN_SPEED } from '../../molstar/core/index.ts';
13
+ import type { Molecule3DHighlight } from '../core/highlight.ts';
13
14
  import type { Measurement, MeasurementKind } from '../core/measurement.ts';
14
15
  import {
15
16
  normalizeMolecule3DSettings,
@@ -21,6 +22,7 @@ import { Molecule3DOptions } from './Molecule3DOptions.tsx';
21
22
  import { Molecule3DStage } from './Molecule3DStage.tsx';
22
23
  import { Molecule3DToolbar } from './Molecule3DToolbar.tsx';
23
24
  import { createMolecule3DViewer } from './createViewer.ts';
25
+ import { highlightColorOf } from './highlightColor.ts';
24
26
  import type { MoleculeViewer3DProps } from './moleculeViewer3DProps.ts';
25
27
  import { useControlledState } from './useControlledState.ts';
26
28
  import { useImageExport } from './useImageExport.ts';
@@ -56,6 +58,7 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
56
58
  spinSpeed = DEFAULT_SPIN_SPEED,
57
59
  measurements: measurementsProp,
58
60
  onMeasurementsChange,
61
+ highlights = NO_HIGHLIGHTS,
59
62
  fileName = 'molecule',
60
63
  background,
61
64
  minHeight = 320,
@@ -133,6 +136,14 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
133
136
  void viewerRef.current?.setMeasureKind(measureKind);
134
137
  }, [container, measureKind]);
135
138
 
139
+ // Kept out of the scene: a new highlight repaints the model, never redraws it.
140
+ useEffect(() => {
141
+ void viewerRef.current?.setHighlights(
142
+ highlights,
143
+ highlightColorOf(container),
144
+ );
145
+ }, [container, highlights]);
146
+
136
147
  const { resetView } = useMoleculeScene({
137
148
  container,
138
149
  viewerRef,
@@ -204,6 +215,8 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
204
215
 
205
216
  const NO_MEASUREMENTS: readonly Measurement[] = [];
206
217
 
218
+ const NO_HIGHLIGHTS: readonly Molecule3DHighlight[] = [];
219
+
207
220
  const STAGE_STYLE: CSSProperties = {
208
221
  position: 'relative',
209
222
  flex: '1 0 auto',
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The colour the 3D view emphasises in, read off the page it sits on.
3
+ *
4
+ * A WebGL colour cannot be a custom property, and the family's accent is the
5
+ * one colour a site owns, so it cannot be written into a shared library either:
6
+ * the view asks the browser what `--accent` resolved to where it is drawn, as
7
+ * the parallel coordinates do, and hands molstar the answer.
8
+ */
9
+
10
+ import { normalizeColor } from '../../tokens/core/colors.ts';
11
+ import { FAMILY_TOKEN_VALUES } from '../../tokens/core/familyTokens.ts';
12
+
13
+ /**
14
+ * What `--accent` resolved to on an element of the view.
15
+ * @param element - An element of the view, once it is on the page, or `null`
16
+ * before it is.
17
+ * @returns The accent as `#rrggbb`. A site that declares none emphasises in its
18
+ * text colour, and a page that declares neither, or no page yet, in the
19
+ * family's.
20
+ */
21
+ export function highlightColorOf(element: Element | null): string {
22
+ return (
23
+ tokenColor(element, '--accent') ??
24
+ tokenColor(element, '--text') ??
25
+ FAMILY_TOKEN_VALUES['--text']
26
+ );
27
+ }
28
+
29
+ function tokenColor(element: Element | null, name: string): string | undefined {
30
+ const resolve = globalThis.getComputedStyle;
31
+ if (element === null || typeof resolve !== 'function') return undefined;
32
+ const color = normalizeColor(resolve(element).getPropertyValue(name));
33
+ return color === null ? undefined : `#${color}`;
34
+ }
@@ -2,6 +2,7 @@ import type { ReactNode } from 'react';
2
2
 
3
3
  import type { ViewerCapability } from '../../orbital/ui/capability.ts';
4
4
  import type { Molecule3DCamera } from '../core/camera.ts';
5
+ import type { Molecule3DHighlight } from '../core/highlight.ts';
5
6
  import type { Measurement } from '../core/measurement.ts';
6
7
  import type {
7
8
  Molecule3DFile,
@@ -80,6 +81,18 @@ export interface MoleculeViewer3DProps {
80
81
  * @default undefined
81
82
  */
82
83
  onMeasurementsChange?: (measurements: readonly Measurement[]) => void;
84
+ /**
85
+ * The parts of the model to emphasise in the site's accent colour, each a
86
+ * bonded path of atoms named as measurements name them: two atoms are that
87
+ * bond, three the two bonds of an angle, four the three bonds of a dihedral,
88
+ * and one atom is that atom alone. Only the bonds between consecutive atoms
89
+ * of one path are emphasised, never another bond between two highlighted
90
+ * atoms, and an atom the structure lacks is skipped. Changing them repaints
91
+ * the model and nothing else: the camera, the measurements and the hover are
92
+ * left as they are.
93
+ * @default [] — nothing is emphasised
94
+ */
95
+ highlights?: readonly Molecule3DHighlight[];
83
96
  /**
84
97
  * Where the camera stands when the first molecule is framed — what a shared
85
98
  * link carries. The camera belongs to whoever is dragging it afterwards, so
@@ -26,7 +26,7 @@ export const MOLECULE_STRUCTURE_REF = 'molecule3d-structure';
26
26
  const MOLECULE_DATA_REF = 'molecule3d-data';
27
27
 
28
28
  /** The drawn model, replaced in place whenever the style changes. */
29
- const MODEL_REPRESENTATION_REF = 'molecule3d-model';
29
+ export const MODEL_REPRESENTATION_REF = 'molecule3d-model';
30
30
 
31
31
  /**
32
32
  * molstar's ball-and-stick radius factor that a size factor of 1 stands for: