Ver Fonte

adder more static label options to structures, various fixes

David Sehnal há 6 anos atrás
pai
commit
ba3eee8cad

+ 4 - 4
src/mol-plugin/state/actions/structure.ts

@@ -69,8 +69,8 @@ export const GroProvider: DataFormatProvider<any> = {
 //
 
 const DownloadStructurePdbIdSourceOptions = PD.Group({
-    supportProps: PD.asOptional(PD.Boolean(false)),
-    asTrajectory: PD.asOptional(PD.Boolean(false, { description: 'Load all entries into a single trajectory.' }))
+    supportProps: PD.Optional(PD.Boolean(false)),
+    asTrajectory: PD.Optional(PD.Boolean(false, { description: 'Load all entries into a single trajectory.' }))
 });
 
 export { DownloadStructure };
@@ -97,7 +97,7 @@ const DownloadStructure = StateAction.build({
                 format: PD.Select('cif', [['cif', 'CIF'], ['pdb', 'PDB']]),
                 isBinary: PD.Boolean(false),
                 options: PD.Group({
-                    supportProps: PD.asOptional(PD.Boolean(false))
+                    supportProps: PD.Optional(PD.Boolean(false))
                 })
             }, { isFlat: true })
         }, {
@@ -242,7 +242,7 @@ export const UpdateTrajectory = StateAction.build({
     display: { name: 'Update Trajectory' },
     params: {
         action: PD.Select<'advance' | 'reset'>('advance', [['advance', 'Advance'], ['reset', 'Reset']]),
-        by: PD.asOptional(PD.Numeric(1, { min: -1, max: 1, step: 1 }))
+        by: PD.Optional(PD.Numeric(1, { min: -1, max: 1, step: 1 }))
     }
 })(({ params, state }) => {
     const models = state.selectQ(q => q.ofTransformer(StateTransforms.Model.ModelFromTrajectory));

+ 6 - 0
src/mol-plugin/state/animation/built-in.ts

@@ -113,6 +113,9 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({
         const update = state.build();
         let changed = false;
         for (const r of reprs) {
+            // TODO: find a better way to handle this, perhaps add a different state object??
+            if (r.transform.transformer === StateTransforms.Representation.StructureLabels3D) continue;
+
             const unwinds = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D, r.transform.ref));
             if (unwinds.length > 0) continue;
 
@@ -180,6 +183,9 @@ export const AnimateUnitsExplode = PluginStateAnimation.create({
         const update = state.build();
         let changed = false;
         for (const r of reprs) {
+            // TODO: find a better way to handle this, perhaps add a different state object??
+            if (r.transform.transformer === StateTransforms.Representation.StructureLabels3D) continue;
+
             const explodes = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.ExplodeStructureRepresentation3D, r.transform.ref));
             if (explodes.length > 0) continue;
 

+ 7 - 7
src/mol-plugin/state/transforms/data.ts

@@ -25,8 +25,8 @@ const Download = PluginStateTransform.BuiltIn({
     to: [SO.Data.String, SO.Data.Binary],
     params: {
         url: PD.Text('https://www.ebi.ac.uk/pdbe/static/entry/1cbs_updated.cif', { description: 'Resource URL. Must be the same domain or support CORS.' }),
-        label: PD.asOptional(PD.Text('')),
-        isBinary: PD.asOptional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' }))
+        label: PD.Optional(PD.Text('')),
+        isBinary: PD.Optional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' }))
     }
 })({
     apply({ params: p }, globalCtx: PluginContext) {
@@ -58,10 +58,10 @@ const DownloadBlob = PluginStateTransform.BuiltIn({
         sources: PD.ObjectList({
             id: PD.Text('', { label: 'Unique ID' }),
             url: PD.Text('https://www.ebi.ac.uk/pdbe/static/entry/1cbs_updated.cif', { description: 'Resource URL. Must be the same domain or support CORS.' }),
-            isBinary: PD.asOptional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' })),
-            canFail: PD.asOptional(PD.Boolean(false, { description: 'Indicate whether the download can fail and not be included in the blob as a result.' }))
+            isBinary: PD.Optional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' })),
+            canFail: PD.Optional(PD.Boolean(false, { description: 'Indicate whether the download can fail and not be included in the blob as a result.' }))
         }, e => `${e.id}: ${e.url}`),
-        maxConcurrency: PD.asOptional(PD.Numeric(4, { min: 1, max: 12, step: 1 }, { description: 'The maximum number of concurrent downloads.' }))
+        maxConcurrency: PD.Optional(PD.Numeric(4, { min: 1, max: 12, step: 1 }, { description: 'The maximum number of concurrent downloads.' }))
     }
 })({
     apply({ params }, plugin: PluginContext) {
@@ -102,8 +102,8 @@ const ReadFile = PluginStateTransform.BuiltIn({
     to: [SO.Data.String, SO.Data.Binary],
     params: {
         file: PD.File(),
-        label: PD.asOptional(PD.Text('')),
-        isBinary: PD.asOptional(PD.Boolean(false, { description: 'If true, open file as as binary (string otherwise)' }))
+        label: PD.Optional(PD.Text('')),
+        isBinary: PD.Optional(PD.Boolean(false, { description: 'If true, open file as as binary (string otherwise)' }))
     }
 })({
     apply({ params: p }) {

+ 1 - 1
src/mol-plugin/state/transforms/misc.ts

@@ -18,7 +18,7 @@ const CreateGroup = PluginStateTransform.BuiltIn({
     to: SO.Group,
     params: {
         label: PD.Text('Group'),
-        description: PD.asOptional(PD.Text(''))
+        description: PD.Optional(PD.Text(''))
     }
 })({
     apply({ params }) {

+ 6 - 6
src/mol-plugin/state/transforms/model.ts

@@ -71,12 +71,12 @@ const TrajectoryFromMmCif = PluginStateTransform.BuiltIn({
     params(a) {
         if (!a) {
             return {
-                blockHeader: PD.asOptional(PD.Text(void 0, { description: 'Header of the block to parse. If none is specifed, the 1st data block in the file is used.' }))
+                blockHeader: PD.Optional(PD.Text(void 0, { description: 'Header of the block to parse. If none is specifed, the 1st data block in the file is used.' }))
             };
         }
         const { blocks } = a.data;
         return {
-            blockHeader: PD.asOptional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' }))
+            blockHeader: PD.Optional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' }))
         };
     }
 })({
@@ -181,12 +181,12 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
     to: SO.Molecule.Structure,
     params(a) {
         if (!a) {
-            return { id: PD.asOptional(PD.Text('', { label: 'Assembly Id', description: 'Assembly Id. Value \'deposited\' can be used to specify deposited asymmetric unit.' })) };
+            return { id: PD.Optional(PD.Text('', { label: 'Assembly Id', description: 'Assembly Id. Value \'deposited\' can be used to specify deposited asymmetric unit.' })) };
         }
         const model = a.data;
         const ids = model.symmetry.assemblies.map(a => [a.id, `${a.id}: ${stringToWords(a.details)}`] as [string, string]);
         ids.push(['deposited', 'Deposited']);
-        return { id: PD.asOptional(PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' })) };
+        return { id: PD.Optional(PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' })) };
     }
 })({
     apply({ a, params }, plugin: PluginContext) {
@@ -258,7 +258,7 @@ const StructureSelection = PluginStateTransform.BuiltIn({
     to: SO.Molecule.Structure,
     params: {
         query: PD.Value<Expression>(MolScriptBuilder.struct.generator.all, { isHidden: true }),
-        label: PD.asOptional(PD.Text('', { isHidden: true }))
+        label: PD.Optional(PD.Text('', { isHidden: true }))
     }
 })({
     apply({ a, params, cache }) {
@@ -295,7 +295,7 @@ const UserStructureSelection = PluginStateTransform.BuiltIn({
     to: SO.Molecule.Structure,
     params: {
         query: PD.ScriptExpression({ language: 'mol-script', expression: '(sel.atom.atom-groups :residue-test (= atom.resname ALA))' }),
-        label: PD.asOptional(PD.Text(''))
+        label: PD.Optional(PD.Text(''))
     }
 })({
     apply({ a, params, cache }) {

+ 9 - 4
src/mol-plugin/state/transforms/representation.ts

@@ -202,9 +202,13 @@ const StructureLabels3D = PluginStateTransform.BuiltIn({
         target: PD.MappedStatic('residues', {
             'elements': PD.Group({ }),
             'residues': PD.Group({ }),
-            'static-text': PD.Group({ value: PD.Text('') }, { isFlat: true })
+            'static-text': PD.Group({
+                value: PD.Text(''),
+                size: PD.Optional(PD.Numeric(1, { min: 1, max: 1000, step: 0.1 })),
+                // TODO: this changes the position while rotated etc... fix
+                position: PD.Optional(Text.Params.attachment)
+            }, { isFlat: true })
         }),
-         // PD.Select<'elements' | 'residues'>('residues', [['residues', 'Residues'], ['elements', 'Elements']]),
         options: PD.Group({
             ...Text.Params,
 
@@ -215,8 +219,9 @@ const StructureLabels3D = PluginStateTransform.BuiltIn({
         })
     }
 })({
-    canAutoUpdate({ a, oldParams, newParams }) {
-        return newParams.target.name === 'static-text' || newParams.target.name === oldParams.target.name
+    canAutoUpdate({ oldParams, newParams }) {
+        return (oldParams.target.name === 'static-text' && newParams.target.name === 'static-text' && oldParams.target.params.value === newParams.target.params.value)
+            || newParams.target.name === oldParams.target.name;
     },
     apply({ a, params }) {
         return Task.create('Structure Labels', async ctx => {

+ 2 - 2
src/mol-plugin/state/transforms/volume.ts

@@ -68,12 +68,12 @@ const VolumeFromDensityServerCif = PluginStateTransform.BuiltIn({
     params(a) {
         if (!a) {
             return {
-                blockHeader: PD.asOptional(PD.Text(void 0, { description: 'Header of the block to parse. If none is specifed, the 1st data block in the file is used.' }))
+                blockHeader: PD.Optional(PD.Text(void 0, { description: 'Header of the block to parse. If none is specifed, the 1st data block in the file is used.' }))
             };
         }
         const blocks = a.data.blocks.slice(1); // zero block contains query meta-data
         return {
-            blockHeader: PD.asOptional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' }))
+            blockHeader: PD.Optional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' }))
         };
     }
 })({

+ 2 - 1
src/mol-plugin/ui/controls/parameters.tsx

@@ -181,7 +181,8 @@ export class NumberInputControl extends React.PureComponent<ParamProps<PD.Numeri
 export class NumberRangeControl extends SimpleParam<PD.Numeric> {
     onChange = (v: number) => { this.update(v); }
     renderControl() {
-        return <Slider value={this.props.value} min={this.props.param.min!} max={this.props.param.max!}
+        const value = typeof this.props.value === 'undefined' ? this.props.param.defaultValue : this.props.value;
+        return <Slider value={value} min={this.props.param.min!} max={this.props.param.max!}
             step={this.props.param.step} onChange={this.onChange} disabled={this.props.isDisabled} onEnter={this.props.onEnter} />
     }
 }

+ 10 - 5
src/mol-plugin/util/structure-labels.ts

@@ -50,20 +50,25 @@ function getLabelsShape(ctx: RuntimeContext, data: LabelsData, props: PD.Values<
 const boundaryHelper = new BoundaryHelper();
 function getLabelData(structure: Structure, params: StateTransformer.Params<StructureLabels3D>): LabelsData {
     if (params.target.name === 'static-text') {
-        return getLabelDataStatic(structure, params.target.params.value);
+        return getLabelDataStatic(structure, params.target.params.value, params.target.params.size || 1, params.target.params.position || 'middle-center');
     } else {
         return getLabelDataComputed(structure, params.target.name);
     }
 
 }
 
-function getLabelDataStatic(structure: Structure, text: string): LabelsData {
+function getLabelDataStatic(structure: Structure, text: string, size: number, position: Text.Params['attachment']['defaultValue']): LabelsData {
     const boundary = structure.boundary.sphere;
+    let oX = 0, oY = 0;
+    if (position.indexOf('left') >= 0) oX = -boundary.radius;
+    if (position.indexOf('right') >= 0) oX = boundary.radius;
+    if (position.indexOf('top') >= 0) oY = boundary.radius;
+    if (position.indexOf('bottom') >= 0) oY = -boundary.radius;
     return {
         texts: [text],
-        positions: [boundary.center],
-        sizes: [1],
-        depths: [boundary.radius]
+        positions: [Vec3.add(Vec3.zero(), boundary.center, Vec3.create(oX, oY, 0))],
+        sizes: [size],
+        depths: [boundary.radius + Math.sqrt(oX * oX + oY * oY)]
     };
 }
 

+ 4 - 3
src/mol-util/param-definition.ts

@@ -36,9 +36,10 @@ export namespace ParamDefinition {
         type: T['type']
     }
 
-    export function asOptional<T>(p: Base<T>): Base<T | undefined> {
-        p.isOptional = true;
-        return p;
+    export function Optional<T>(p: Base<T>): Base<T | undefined> {
+        const ret = { ...p };
+        ret.isOptional = true;
+        return ret;
     }
 
     export interface Value<T> extends Base<T> {