123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
- import { ElementIndex, Model, CustomPropertyDescriptor } from '../../mol-model/structure';
- import { StructureElement } from '../../mol-model/structure/structure';
- import { Location } from '../../mol-model/location';
- import { ThemeDataContext } from '../../mol-theme/theme';
- import { ColorTheme, LocationColor } from '../../mol-theme/color';
- import { Color } from '../../mol-util/color';
- import { Loci } from '../../mol-model/loci';
- import { OrderedSet } from '../../mol-data/int';
- import { CustomModelProperty } from './custom-model-property';
- import { CustomProperty } from './custom-property';
- import { LociLabelProvider } from '../../mol-plugin-state/manager/loci-label';
- export { CustomElementProperty };
- interface CustomElementProperty<T> {
- propertyProvider: CustomModelProperty.Provider<{}, CustomElementProperty.Value<T>>
- colorThemeProvider?: ColorTheme.Provider<{}>
- labelProvider?: LociLabelProvider
- }
- namespace CustomElementProperty {
- export type Value<T> = Map<ElementIndex, T>
- export interface Builder<T> {
- label: string
- name: string
- getData(model: Model, ctx?: CustomProperty.Context): Value<T> | Promise<Value<T>>
- coloring?: {
- getColor: (p: T) => Color
- defaultColor: Color
- }
- getLabel?: (p: T) => string | undefined
- isApplicable?: (data: Model) => boolean,
- type?: 'dynamic' | 'static',
- }
- export function create<T>(builder: Builder<T>): CustomElementProperty<T> {
- const modelProperty = createModelProperty(builder)
- return {
- propertyProvider: modelProperty,
- colorThemeProvider: builder.coloring?.getColor && createColorThemeProvider(modelProperty, builder.coloring.getColor, builder.coloring.defaultColor),
- labelProvider: builder.getLabel && createLabelProvider(modelProperty, builder.getLabel)
- }
- }
- function createModelProperty<T>(builder: Builder<T>) {
- return CustomModelProperty.createProvider({
- label: builder.label,
- descriptor: CustomPropertyDescriptor({
- name: builder.name,
- }),
- type: builder.type || 'dynamic',
- defaultParams: {},
- getParams: (data: Model) => ({}),
- isApplicable: (data: Model) => !!builder.isApplicable?.(data),
- obtain: async (ctx: CustomProperty.Context, data: Model) => {
- return await builder.getData(data, ctx)
- }
- })
- }
- function createColorThemeProvider<T>(modelProperty: CustomModelProperty.Provider<{}, Value<T>>, getColor: (p: T) => Color, defaultColor: Color): ColorTheme.Provider<{}> {
- function Coloring(ctx: ThemeDataContext, props: {}): ColorTheme<{}> {
- let color: LocationColor;
- const property = ctx.structure && modelProperty.get(ctx.structure.models[0])
- const contextHash = property?.version
- if (property?.value && ctx.structure) {
- const data = property.value
- color = (location: Location) => {
- if (StructureElement.Location.is(location)) {
- const e = data.get(location.element);
- if (typeof e !== 'undefined') return getColor(e);
- }
- return defaultColor;
- }
- } else {
- color = () => defaultColor;
- }
- return {
- factory: Coloring,
- granularity: 'group',
- color: color,
- props: props,
- contextHash,
- description: `Assign element colors based on '${modelProperty.label}' data.`
- };
- }
- return {
- name: modelProperty.descriptor.name,
- label: modelProperty.label,
- category: 'Custom',
- factory: Coloring,
- getParams: () => ({}),
- defaultValues: {},
- isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && !!modelProperty.get(ctx.structure.models[0]).value,
- ensureCustomProperties: {
- attach: (ctx: CustomProperty.Context, data: ThemeDataContext) => data.structure ? modelProperty.attach(ctx, data.structure.models[0], void 0, true) : Promise.resolve(),
- detach: (_, data: ThemeDataContext) => data.structure && data.structure.models[0].customProperties.reference(modelProperty.descriptor, false)
- }
- }
- }
- function createLabelProvider<T>(modelProperty: CustomModelProperty.Provider<{}, Value<T>>, getLabel: (p: T) => string | undefined) {
- return function(loci: Loci): string | undefined {
- if (loci.kind === 'element-loci') {
- const e = loci.elements[0];
- if (!e) return
- const data = modelProperty.get(e.unit.model).value
- const element = e.unit.elements[OrderedSet.start(e.indices)]
- const value = data?.get(element)
- if (value === undefined) return
- return getLabel(value);
- }
- return
- }
- }
- }
|