From 7094f8f2651dfb0c83baec98ff9c1d2cf0468c87 Mon Sep 17 00:00:00 2001 From: dsehnal <david.sehnal@gmail.com> Date: Wed, 24 Aug 2022 15:26:24 +0200 Subject: [PATCH] Improve Viewer theming & label customization --- CHANGELOG.md | 3 ++ src/apps/viewer/app.ts | 3 +- src/apps/viewer/embedded.html | 9 ++++ src/mol-plugin-state/actions/structure.ts | 3 +- .../structure/representation-preset.ts | 46 ++++++++++--------- 5 files changed, 41 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 533e376c0..ba1e938af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] +- Support ``globalColorParams`` and ``globalSymmetryParams`` in common representation params +- Support ``label`` parameter in ``Viewer.loadStructureFromUrl`` + ## [v3.15.0] - 2022-08-23 - Fix wboit in Safari >=15 (add missing depth renderbuffer to wboit pass) diff --git a/src/apps/viewer/app.ts b/src/apps/viewer/app.ts index 8a27a9a4c..4c8df4e1b 100644 --- a/src/apps/viewer/app.ts +++ b/src/apps/viewer/app.ts @@ -199,7 +199,7 @@ export class Viewer { return PluginCommands.State.Snapshots.OpenUrl(this.plugin, { url, type }); } - loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) { + loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions & { label?: string }) { const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin); return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, { source: { @@ -208,6 +208,7 @@ export class Viewer { url: Asset.Url(url), format: format as any, isBinary, + label: options?.label, options: { ...params.source.params.options, representationParams: options?.representationParams as any }, } } diff --git a/src/apps/viewer/embedded.html b/src/apps/viewer/embedded.html index 8533dc365..a309a84bd 100644 --- a/src/apps/viewer/embedded.html +++ b/src/apps/viewer/embedded.html @@ -38,6 +38,15 @@ viewer.loadPdb('7bv2'); viewer.loadEmdb('EMD-30210', { detail: 6 }); // viewer.loadAllModelsOrAssemblyFromUrl('https://cs.litemol.org/5ire/full', 'mmcif', false, { representationParams: { theme: { globalName: 'operator-name' } } }) + // viewer.loadStructureFromUrl('my url', 'pdb', false, { + // representationParams: { + // theme: { + // globalName: 'uniform', + // globalColorParams: { value: 0xff0000 } + // } + // }, + // label: 'my structure' + // }); }); </script> </body> diff --git a/src/mol-plugin-state/actions/structure.ts b/src/mol-plugin-state/actions/structure.ts index 630c5d0cd..61765b5a2 100644 --- a/src/mol-plugin-state/actions/structure.ts +++ b/src/mol-plugin-state/actions/structure.ts @@ -90,6 +90,7 @@ const DownloadStructure = StateAction.build({ url: PD.Url(''), format: PD.Select<BuiltInTrajectoryFormat>('mmcif', PD.arrayToOptions(BuiltInTrajectoryFormats.map(f => f[0]), f => f)), isBinary: PD.Boolean(false), + label: PD.Optional(PD.Text('')), options }, { isFlat: true, label: 'URL' }) }) @@ -104,7 +105,7 @@ const DownloadStructure = StateAction.build({ switch (src.name) { case 'url': - downloadParams = [{ url: src.params.url, isBinary: src.params.isBinary }]; + downloadParams = [{ url: src.params.url, isBinary: src.params.isBinary, label: src.params.label || undefined }]; format = src.params.format; break; case 'pdb': diff --git a/src/mol-plugin-state/builder/structure/representation-preset.ts b/src/mol-plugin-state/builder/structure/representation-preset.ts index b581666d5..25f2d1f90 100644 --- a/src/mol-plugin-state/builder/structure/representation-preset.ts +++ b/src/mol-plugin-state/builder/structure/representation-preset.ts @@ -41,8 +41,10 @@ export namespace StructureRepresentationPresetProvider { quality: PD.Optional(PD.Select<VisualQuality>('auto', VisualQualityOptions)), theme: PD.Optional(PD.Group({ globalName: PD.Optional(PD.Text<ColorTheme.BuiltIn>('')), + globalColorParams: PD.Optional(PD.Value<any>({}, { isHidden: true })), carbonColor: PD.Optional(PD.Select('chain-id', PD.arrayToOptions(['chain-id', 'operator-name', 'element-symbol'] as const))), symmetryColor: PD.Optional(PD.Text<ColorTheme.BuiltIn>('')), + symmetryColorParams: PD.Optional(PD.Value<any>({}, { isHidden: true })), focus: PD.Optional(PD.Group({ name: PD.Optional(PD.Text<ColorTheme.BuiltIn>('')), params: PD.Optional(PD.Value<ColorTheme.BuiltInParams<ColorTheme.BuiltIn>>({} as any)) @@ -76,13 +78,15 @@ export namespace StructureRepresentationPresetProvider { if (params.ignoreLight !== void 0) typeParams.ignoreLight = !!params.ignoreLight; const color: ColorTheme.BuiltIn | undefined = params.theme?.globalName ? params.theme?.globalName : void 0; const ballAndStickColor: ColorTheme.BuiltInParams<'element-symbol'> = params.theme?.carbonColor !== undefined - ? { carbonColor: getCarbonColorParams(params.theme?.carbonColor) } - : { }; + ? { carbonColor: getCarbonColorParams(params.theme?.carbonColor), ...params.theme?.globalColorParams } + : { ...params.theme?.globalColorParams }; const symmetryColor: ColorTheme.BuiltIn | undefined = structure && params.theme?.symmetryColor ? isSymmetry(structure) ? params.theme?.symmetryColor : color : color; + const symmetryColorParams = params.theme?.symmetryColorParams ? { ...params.theme?.globalColorParams, ...params.theme?.symmetryColorParams } : { ...params.theme?.globalColorParams }; + const globalColorParams = params.theme?.globalColorParams ? { ...params.theme?.globalColorParams } : undefined; - return { update, builder, color, symmetryColor, typeParams, ballAndStickColor }; + return { update, builder, color, symmetryColor, symmetryColorParams, globalColorParams, typeParams, ballAndStickColor }; } export function updateFocusRepr<T extends ColorTheme.BuiltIn>(plugin: PluginContext, structure: Structure, themeName: T | undefined, themeParams: ColorTheme.BuiltInParams<T> | undefined) { @@ -177,18 +181,18 @@ const polymerAndLigand = StructureRepresentationPresetProvider({ const waterType = (components.water?.obj?.data?.elementCount || 0) > 50_000 ? 'line' : 'ball-and-stick'; const lipidType = (components.lipid?.obj?.data?.elementCount || 0) > 20_000 ? 'line' : 'ball-and-stick'; - const { update, builder, typeParams, color, symmetryColor, ballAndStickColor } = reprBuilder(plugin, params, structure); + const { update, builder, typeParams, color, symmetryColor, symmetryColorParams, globalColorParams, ballAndStickColor } = reprBuilder(plugin, params, structure); const representations = { - polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams, ...cartoonProps }, color: symmetryColor }, { tag: 'polymer' }), + polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams, ...cartoonProps }, color: symmetryColor, colorParams: symmetryColorParams }, { tag: 'polymer' }), ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams, color, colorParams: ballAndStickColor }, { tag: 'ligand' }), nonStandard: builder.buildRepresentation(update, components.nonStandard, { type: 'ball-and-stick', typeParams, color, colorParams: ballAndStickColor }, { tag: 'non-standard' }), branchedBallAndStick: builder.buildRepresentation(update, components.branched, { type: 'ball-and-stick', typeParams: { ...typeParams, alpha: 0.3 }, color, colorParams: ballAndStickColor }, { tag: 'branched-ball-and-stick' }), - branchedSnfg3d: builder.buildRepresentation(update, components.branched, { type: 'carbohydrate', typeParams, color }, { tag: 'branched-snfg-3d' }), - water: builder.buildRepresentation(update, components.water, { type: waterType, typeParams: { ...typeParams, alpha: 0.6, visuals: waterType === 'line' ? ['intra-bond', 'element-point'] : undefined }, color, colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'water' }), - ion: builder.buildRepresentation(update, components.ion, { type: 'ball-and-stick', typeParams, color, colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ion' }), - lipid: builder.buildRepresentation(update, components.lipid, { type: lipidType, typeParams: { ...typeParams, alpha: 0.6, visuals: lipidType === 'line' ? ['intra-bond'] : undefined }, color, colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'lipid' }), - coarse: builder.buildRepresentation(update, components.coarse, { type: 'spacefill', typeParams, color: color || 'chain-id' }, { tag: 'coarse' }) + branchedSnfg3d: builder.buildRepresentation(update, components.branched, { type: 'carbohydrate', typeParams, color, colorParams: globalColorParams }, { tag: 'branched-snfg-3d' }), + water: builder.buildRepresentation(update, components.water, { type: waterType, typeParams: { ...typeParams, alpha: 0.6, visuals: waterType === 'line' ? ['intra-bond', 'element-point'] : undefined }, color, colorParams: { carbonColor: { name: 'element-symbol', params: {} }, ...globalColorParams } }, { tag: 'water' }), + ion: builder.buildRepresentation(update, components.ion, { type: 'ball-and-stick', typeParams, color, colorParams: { carbonColor: { name: 'element-symbol', params: {} }, ...globalColorParams } }, { tag: 'ion' }), + lipid: builder.buildRepresentation(update, components.lipid, { type: lipidType, typeParams: { ...typeParams, alpha: 0.6, visuals: lipidType === 'line' ? ['intra-bond'] : undefined }, color, colorParams: { carbonColor: { name: 'element-symbol', params: {} }, ...globalColorParams } }, { tag: 'lipid' }), + coarse: builder.buildRepresentation(update, components.coarse, { type: 'spacefill', typeParams, color: color || 'chain-id', colorParams: globalColorParams }, { tag: 'coarse' }) }; await update.commit({ revertOnError: false }); @@ -223,11 +227,11 @@ const proteinAndNucleic = StructureRepresentationPresetProvider({ smoothness: structure.isCoarseGrained ? 1.0 : 1.5, }; - const { update, builder, typeParams, symmetryColor } = reprBuilder(plugin, params, structure); + const { update, builder, typeParams, symmetryColor, symmetryColorParams } = reprBuilder(plugin, params, structure); const representations = { - protein: builder.buildRepresentation(update, components.protein, { type: 'cartoon', typeParams: { ...typeParams, ...cartoonProps }, color: symmetryColor }, { tag: 'protein' }), - nucleic: builder.buildRepresentation(update, components.nucleic, { type: 'gaussian-surface', typeParams: { ...typeParams, ...gaussianProps }, color: symmetryColor }, { tag: 'nucleic' }) + protein: builder.buildRepresentation(update, components.protein, { type: 'cartoon', typeParams: { ...typeParams, ...cartoonProps }, color: symmetryColor, colorParams: symmetryColorParams }, { tag: 'protein' }), + nucleic: builder.buildRepresentation(update, components.nucleic, { type: 'gaussian-surface', typeParams: { ...typeParams, ...gaussianProps }, color: symmetryColor, colorParams: symmetryColorParams }, { tag: 'nucleic' }) }; await update.commit({ revertOnError: true }); @@ -275,11 +279,11 @@ const coarseSurface = StructureRepresentationPresetProvider({ }); } - const { update, builder, typeParams, symmetryColor } = reprBuilder(plugin, params, structure); + const { update, builder, typeParams, symmetryColor, symmetryColorParams } = reprBuilder(plugin, params, structure); const representations = { - polymer: builder.buildRepresentation(update, components.polymer, { type: 'gaussian-surface', typeParams: { ...typeParams, ...gaussianProps }, color: symmetryColor }, { tag: 'polymer' }), - lipid: builder.buildRepresentation(update, components.lipid, { type: 'gaussian-surface', typeParams: { ...typeParams, ...gaussianProps }, color: symmetryColor }, { tag: 'lipid' }) + polymer: builder.buildRepresentation(update, components.polymer, { type: 'gaussian-surface', typeParams: { ...typeParams, ...gaussianProps }, color: symmetryColor, colorParams: symmetryColorParams }, { tag: 'polymer' }), + lipid: builder.buildRepresentation(update, components.lipid, { type: 'gaussian-surface', typeParams: { ...typeParams, ...gaussianProps }, color: symmetryColor, colorParams: symmetryColorParams }, { tag: 'lipid' }) }; await update.commit({ revertOnError: true }); @@ -309,10 +313,10 @@ const polymerCartoon = StructureRepresentationPresetProvider({ sizeFactor: structure.isCoarseGrained ? 0.8 : 0.2 }; - const { update, builder, typeParams, symmetryColor } = reprBuilder(plugin, params, structure); + const { update, builder, typeParams, symmetryColor, symmetryColorParams } = reprBuilder(plugin, params, structure); const representations = { - polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams, ...cartoonProps }, color: symmetryColor }, { tag: 'polymer' }) + polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams, ...cartoonProps }, color: symmetryColor, colorParams: symmetryColorParams }, { tag: 'polymer' }) }; await update.commit({ revertOnError: true }); @@ -367,9 +371,9 @@ const atomicDetail = StructureRepresentationPresetProvider({ }); } - const { update, builder, typeParams, color, ballAndStickColor } = reprBuilder(plugin, params, structure); + const { update, builder, typeParams, color, ballAndStickColor, globalColorParams } = reprBuilder(plugin, params, structure); const colorParams = lowResidueElementRatio && !bondsGiven - ? { carbonColor: { name: 'element-symbol', params: {} } } + ? { carbonColor: { name: 'element-symbol', params: {} }, ...globalColorParams } : ballAndStickColor; const representations = { @@ -377,7 +381,7 @@ const atomicDetail = StructureRepresentationPresetProvider({ }; if (showCarbohydrateSymbol) { Object.assign(representations, { - snfg3d: builder.buildRepresentation(update, components.branched, { type: 'carbohydrate', typeParams: { ...typeParams, alpha: 0.4, visuals: ['carbohydrate-symbol'] }, color }, { tag: 'snfg-3d' }), + snfg3d: builder.buildRepresentation(update, components.branched, { type: 'carbohydrate', typeParams: { ...typeParams, alpha: 0.4, visuals: ['carbohydrate-symbol'] }, color, colorParams: globalColorParams }, { tag: 'snfg-3d' }), }); } -- GitLab