/** * Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Adam Midlik */ import { Location } from '../../../mol-model/location'; import { Bond, StructureElement } from '../../../mol-model/structure'; import { ColorTheme, LocationColor } from '../../../mol-theme/color'; import { ThemeDataContext } from '../../../mol-theme/theme'; import { ColorNames } from '../../../mol-util/color/names'; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; import { decodeColor } from '../helpers/utils'; import { getMVSAnnotationForStructure } from './annotation-prop'; import { isMVSStructure } from './is-mvs-model-prop'; /** Parameter definition for color theme "MVS Annotation" */ export const MVSAnnotationColorThemeParams = { annotationId: PD.Text('', { description: 'Reference to "Annotation" custom model property' }), fieldName: PD.Text('color', { description: 'Annotation field (column) from which to take color values' }), background: PD.Color(ColorNames.gainsboro, { description: 'Color for elements without annotation' }), }; export type MVSAnnotationColorThemeParams = typeof MVSAnnotationColorThemeParams /** Parameter values for color theme "MVS Annotation" */ export type MVSAnnotationColorThemeProps = PD.Values /** Return color theme that assigns colors based on an annotation file. * The annotation file itself is handled by a custom model property (`MVSAnnotationsProvider`), * the color theme then just uses this property. */ export function MVSAnnotationColorTheme(ctx: ThemeDataContext, props: MVSAnnotationColorThemeProps): ColorTheme { let color: LocationColor = () => props.background; if (ctx.structure && !ctx.structure.isEmpty) { const { annotation } = getMVSAnnotationForStructure(ctx.structure, props.annotationId); if (annotation) { const colorForStructureElementLocation = (location: StructureElement.Location) => { // if (annot.getAnnotationForLocation(location)?.color !== annot.getAnnotationForLocation_Reference(location)?.color) throw new Error('AssertionError'); return decodeColor(annotation?.getValueForLocation(location, props.fieldName)) ?? props.background; }; const auxLocation = StructureElement.Location.create(ctx.structure); color = (location: Location) => { if (StructureElement.Location.is(location)) { return colorForStructureElementLocation(location); } else if (Bond.isLocation(location)) { // this will be applied for each bond twice, to get color of each half (a* refers to the adjacent atom, b* to the opposite atom) auxLocation.unit = location.aUnit; auxLocation.element = location.aUnit.elements[location.aIndex]; return colorForStructureElementLocation(auxLocation); } return props.background; }; } else { console.error(`Annotation source "${props.annotationId}" not present`); } } return { factory: MVSAnnotationColorTheme, granularity: 'group', preferSmoothing: true, color: color, props: props, description: 'Assigns colors based on custom MolViewSpec annotation data.', }; } /** A thingy that is needed to register color theme "MVS Annotation" */ export const MVSAnnotationColorThemeProvider: ColorTheme.Provider = { name: 'mvs-annotation', label: 'MVS Annotation', category: ColorTheme.Category.Misc, factory: MVSAnnotationColorTheme, getParams: ctx => MVSAnnotationColorThemeParams, defaultValues: PD.getDefaultValues(MVSAnnotationColorThemeParams), isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && isMVSStructure(ctx.structure), };