Skip to content

Commit c6f23fb

Browse files
committed
Custom tooltips support
1 parent a519ec2 commit c6f23fb

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file, following t
1515
- Improved performance
1616
- Allows `color: null` (do not apply color)
1717
- `keepColors` and `keepRepresentations` parameters to avoid clearing previous selections
18+
- Added `.visual.tooltips` and `.visual.clearTooltips`
1819
- Built files don't contain package version in the filename
1920

2021
## [v3.1.3]

index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,19 @@ <h4>Set highlight / selection colour</h4>
177177
Reset
178178
</button>
179179

180+
<h4>Custom tooltips</h4>
181+
<button onclick="viewerInstance.visual.tooltips({ data: [
182+
{ struct_asym_id: 'A', tooltip: 'Custom tooltip for chain A' },
183+
{ struct_asym_id: 'B', tooltip: 'Custom tooltip for chain B' },
184+
{ struct_asym_id: 'C', tooltip: 'Custom tooltip for chain C' },
185+
{ struct_asym_id: 'D', tooltip: 'Custom tooltip for chain D' },
186+
] });">
187+
Add tooltips
188+
</button>
189+
<button onclick="viewerInstance.visual.clearTooltips();">
190+
Clear
191+
</button>
192+
180193
<h4>Reset Visual</h4>
181194
<button onclick="viewerInstance.visual.reset({ camera: true })">
182195
Camera

src/app/index.ts

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { GeometryExport } from 'Molstar/extensions/geo-export';
22
import { MAQualityAssessment } from 'Molstar/extensions/model-archive/quality-assessment/behavior';
33
import { Mp4Export } from 'Molstar/extensions/mp4-export';
4+
import { MolViewSpec } from 'Molstar/extensions/mvs/behavior';
5+
import { CustomTooltipsProps, CustomTooltipsProvider } from 'Molstar/extensions/mvs/components/custom-tooltips-prop';
46
import { PDBeStructureQualityReport } from 'Molstar/extensions/pdbe';
57
import { RCSBAssemblySymmetry, RCSBAssemblySymmetryConfig } from 'Molstar/extensions/rcsb/assembly-symmetry/behavior';
68
import { Canvas3DProps } from 'Molstar/mol-canvas3d/canvas3d';
@@ -18,7 +20,7 @@ import { clearStructureOverpaint } from 'Molstar/mol-plugin-state/helpers/struct
1820
import { createStructureRepresentationParams } from 'Molstar/mol-plugin-state/helpers/structure-representation-params';
1921
import { PluginStateObject } from 'Molstar/mol-plugin-state/objects';
2022
import { StateTransforms } from 'Molstar/mol-plugin-state/transforms';
21-
import { StructureComponent } from 'Molstar/mol-plugin-state/transforms/model';
23+
import { CustomStructureProperties, StructureComponent } from 'Molstar/mol-plugin-state/transforms/model';
2224
import { StructureRepresentation3D } from 'Molstar/mol-plugin-state/transforms/representation';
2325
import { createPluginUI } from 'Molstar/mol-plugin-ui/react18';
2426
import { PluginUISpec } from 'Molstar/mol-plugin-ui/spec';
@@ -100,6 +102,8 @@ export class PDBeMolstarPlugin {
100102
const pdbePluginSpec: PluginUISpec = DefaultPluginUISpec();
101103
pdbePluginSpec.config ??= [];
102104

105+
pdbePluginSpec.behaviors.push(PluginSpec.Behavior(MolViewSpec));
106+
103107
if (!this.initParams.ligandView && !this.initParams.superposition && this.initParams.selectInteraction) {
104108
pdbePluginSpec.behaviors.push(PluginSpec.Behavior(StructureFocusRepresentation));
105109
}
@@ -531,7 +535,7 @@ export class PDBeMolstarPlugin {
531535
if (this.isHighlightColorUpdated) this.visual.reset({ highlightColor: true });
532536
},
533537

534-
/** `structureNumber` counts from 1; if not provided, select will be applied to all load structures.
538+
/** `structureNumber` counts from 1; if not provided, select will be applied to all loaded structures.
535539
* Use `keepColors` and/or `keepRepresentations` to preserve currently active selection.
536540
*/
537541
select: async (params: { data: QueryParam[], nonSelectedColor?: any, structureNumber?: number, keepColors?: boolean, keepRepresentations?: boolean }) => {
@@ -767,6 +771,48 @@ export class PDBeMolstarPlugin {
767771
await PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { renderer, marking } });
768772
}
769773
},
774+
775+
/** Add interactive tooltips to parts of the structure. The added tooltips will be shown on a separate line in the tooltip box.
776+
* Repeated call to this function removes any previously added tooltips.
777+
* `structureNumber` counts from 1; if not provided, tooltips will be applied to all loaded structures.
778+
* Example: `await this.visual.tooltips({ data: [{ struct_asym_id: 'A', tooltip: 'Chain A' }, { struct_asym_id: 'B', tooltip: 'Chain B' }] });`. */
779+
tooltips: async (params: { data: QueryParam[], structureNumber?: number }) => {
780+
// Structure list to apply tooltips
781+
let structures = this.plugin.managers.structure.hierarchy.current.structures.map((structureRef, i) => ({ structureRef, number: i + 1 }));
782+
if (params.structureNumber !== undefined) {
783+
structures = [structures[params.structureNumber - 1]];
784+
}
785+
786+
for (const struct of structures) {
787+
const selections = this.getSelections(params.data, struct.number);
788+
const customTooltipProps: CustomTooltipsProps = {
789+
tooltips: selections.map(s => ({ text: s.param.tooltip ?? '', selector: { name: 'bundle', params: s.bundle } })),
790+
};
791+
792+
const structRef = struct.structureRef.cell.transform.ref;
793+
let customPropsCells = this.plugin.state.data.select(StateSelection.Generators.ofTransformer(CustomStructureProperties, structRef));
794+
if (customPropsCells.length === 0) {
795+
await this.plugin.build().to(structRef).apply(CustomStructureProperties).commit();
796+
customPropsCells = this.plugin.state.data.select(StateSelection.Generators.ofTransformer(CustomStructureProperties, structRef));
797+
}
798+
799+
await this.plugin.build().to(customPropsCells[0]).update(old => ({
800+
properties: {
801+
...old.properties,
802+
[CustomTooltipsProvider.descriptor.name]: customTooltipProps,
803+
},
804+
autoAttach: old.autoAttach.includes(CustomTooltipsProvider.descriptor.name) ?
805+
old.autoAttach
806+
: [...old.autoAttach, CustomTooltipsProvider.descriptor.name],
807+
})).commit();
808+
}
809+
810+
},
811+
812+
/** Remove any tooltips added by `this.visual.tooltips`. */
813+
clearTooltips: async (structureNumber?: number) => {
814+
await this.visual.tooltips({ data: [], structureNumber });
815+
},
770816
};
771817

772818
async clear() {

0 commit comments

Comments
 (0)