mirror of
https://github.com/molstar/molstar.git
synced 2026-06-07 23:34:23 +08:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d29bf2eec2 | ||
|
|
5db60c2882 | ||
|
|
737846e093 | ||
|
|
2ad551bdc7 | ||
|
|
46fa581f07 | ||
|
|
17dbe4b60e | ||
|
|
aeaf2e799a | ||
|
|
ef16b718c4 | ||
|
|
ab4130d42d | ||
|
|
9e73de89fb | ||
|
|
02cec6f8e6 | ||
|
|
e97a02473f | ||
|
|
22e5c9d65b | ||
|
|
10d9120d37 | ||
|
|
e6c20d35bd | ||
|
|
27bf66038d | ||
|
|
3ce6d89521 | ||
|
|
24608ac355 | ||
|
|
da034d9502 | ||
|
|
581673fb9b | ||
|
|
29cf97e6cf | ||
|
|
f65773d654 | ||
|
|
d11c8c166a | ||
|
|
ae6bd743a8 | ||
|
|
c1654574d0 | ||
|
|
6f506351cd | ||
|
|
db83b97ff9 | ||
|
|
302e1c659f | ||
|
|
8b4d987f94 | ||
|
|
3fe80fe61a | ||
|
|
3e6d0c8c62 | ||
|
|
c6210ae1a0 | ||
|
|
36cf2853b2 | ||
|
|
70ebdc6b80 | ||
|
|
5934f355c2 | ||
|
|
225d051dd6 | ||
|
|
c59ae908b8 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -6,6 +6,20 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v3.45.0] - 2023-02-03
|
||||
|
||||
- Add color interpolation to impostor cylinders
|
||||
- MolViewSpec components are applicable only when the model has been loaded from MolViewSpec
|
||||
- Add `snapshotKey` and `tooltip` params to loci `LabelRepresentation`
|
||||
- Update `FocusLoci` behavior to support `snapshotKey` param
|
||||
- Clicking a visual with `snapshotKey` will trigger that snapshot
|
||||
- Render multiline loci label tooltips as Markdown
|
||||
- `ParamDefinition.Text` updates:
|
||||
- Support `multiline` inputs
|
||||
- Support `placeholder` parameter
|
||||
- Support `disableInteractiveUpdates` to only trigger updates once the control loses focus
|
||||
- Move dependencies related to the headless context from optional deps to optional peer deps
|
||||
|
||||
## [v3.44.0] - 2023-01-06
|
||||
|
||||
- Add new `cartoon` visuals to support atomic nucleotide base with sugar
|
||||
|
||||
953
package-lock.json
generated
953
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
54
package.json
54
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.44.0",
|
||||
"version": "3.45.0",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -113,22 +113,21 @@
|
||||
"@graphql-codegen/time": "^5.0.0",
|
||||
"@graphql-codegen/typescript": "^4.0.1",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "^3.0.0",
|
||||
"@graphql-codegen/typescript-graphql-request": "^6.1.0",
|
||||
"@graphql-codegen/typescript-graphql-request": "^6.2.0",
|
||||
"@graphql-codegen/typescript-operations": "^4.0.1",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/gl": "^6.0.5",
|
||||
"@types/jpeg-js": "^0.3.7",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/react": "^18.2.47",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/react": "^18.2.52",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@typescript-eslint/eslint-plugin": "^6.18.0",
|
||||
"@typescript-eslint/parser": "^6.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
||||
"@typescript-eslint/parser": "^6.20.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"concurrently": "^8.2.2",
|
||||
"cpx2": "^6.0.1",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.8.1",
|
||||
"css-loader": "^6.10.0",
|
||||
"eslint": "^8.56.0",
|
||||
"extra-watch-webpack-plugin": "^1.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
@@ -136,19 +135,20 @@
|
||||
"graphql": "^16.8.1",
|
||||
"http-server": "^14.1.1",
|
||||
"jest": "^29.7.0",
|
||||
"mini-css-extract-plugin": "^2.7.6",
|
||||
"jpeg-js": "^0.4.4",
|
||||
"mini-css-extract-plugin": "^2.8.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"sass": "^1.69.7",
|
||||
"sass-loader": "^13.3.3",
|
||||
"sass": "^1.70.0",
|
||||
"sass-loader": "^14.1.0",
|
||||
"simple-git": "^3.22.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"style-loader": "^3.3.3",
|
||||
"ts-jest": "^29.1.1",
|
||||
"style-loader": "^3.3.4",
|
||||
"ts-jest": "^29.1.2",
|
||||
"typescript": "^5.3.3",
|
||||
"webpack": "^5.89.0",
|
||||
"webpack": "^5.90.1",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -157,7 +157,7 @@
|
||||
"@types/compression": "1.7.5",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^16.18.69",
|
||||
"@types/node-fetch": "^2.6.10",
|
||||
"@types/node-fetch": "^2.6.11",
|
||||
"@types/swagger-ui-dist": "3.30.4",
|
||||
"argparse": "^2.0.1",
|
||||
"body-parser": "^1.20.2",
|
||||
@@ -171,19 +171,31 @@
|
||||
"node-fetch": "^2.7.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"rxjs": "^7.8.1",
|
||||
"swagger-ui-dist": "^5.10.5",
|
||||
"swagger-ui-dist": "^5.11.2",
|
||||
"tslib": "^2.6.2",
|
||||
"util.promisify": "^1.1.2",
|
||||
"xhr2": "^0.2.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.1.0 || ^17.0.2 || ^16.14.0",
|
||||
"react-dom": "^18.1.0 || ^17.0.2 || ^16.14.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"canvas": "^2.11.2",
|
||||
"gl": "^6.0.2",
|
||||
"jpeg-js": "^0.4.4",
|
||||
"pngjs": "^6.0.0"
|
||||
"pngjs": "^6.0.0",
|
||||
"react": "^18.1.0 || ^17.0.2 || ^16.14.0",
|
||||
"react-dom": "^18.1.0 || ^17.0.2 || ^16.14.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"canvas": {
|
||||
"optional": true
|
||||
},
|
||||
"gl": {
|
||||
"optional": true
|
||||
},
|
||||
"jpeg-js": {
|
||||
"optional": true
|
||||
},
|
||||
"pngjs": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,8 +158,8 @@ async function ensureDicAvailable(dicPath: string, dicUrl: string) {
|
||||
const DIC_DIR = path.resolve(__dirname, '../../../../build/dics/');
|
||||
const MMCIF_DIC_PATH = `${DIC_DIR}/mmcif_pdbx_v50.dic`;
|
||||
const MMCIF_DIC_URL = 'http://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic';
|
||||
const IHM_DIC_PATH = `${DIC_DIR}/ihm-extension.dic`;
|
||||
const IHM_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/IHM-dictionary/master/ihm-extension.dic';
|
||||
const IHM_DIC_PATH = `${DIC_DIR}/mmcif_ihm_ext.dic`;
|
||||
const IHM_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/IHMCIF/master/dist/mmcif_ihm_ext.dic';
|
||||
const MA_DIC_PATH = `${DIC_DIR}/ma-extension.dic`;
|
||||
const MA_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/ModelCIF/master/dist/mmcif_ma.dic';
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ const meshShapeProviderParams: Mesh.Params = {
|
||||
quality: PD.Select<VisualQuality>('custom', VisualQualityOptions, { isEssential: true, description: 'Visual/rendering quality of the representation.' }), // use 'custom' when wanting to apply doubleSided
|
||||
doubleSided: PD.Boolean(true, BaseGeometry.CustomQualityParamInfo),
|
||||
// set `flatShaded`: true to see the real mesh vertices and triangles
|
||||
transparentBackfaces: PD.Select('on', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory), // 'on' means: show backfaces with correct opacity, even when opacity < 1 (requires doubleSided) ¯\_(ツ)_/¯
|
||||
transparentBackfaces: PD.Select('on', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory), // 'on' means: show backfaces with correct opacity, even when opacity < 1 (requires doubleSided) ¯\_(ツ)_/¯
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
@@ -22,6 +22,7 @@ import { MVSAnnotationTooltipsLabelProvider, MVSAnnotationTooltipsProvider } fro
|
||||
import { CustomLabelRepresentationProvider } from './components/custom-label/representation';
|
||||
import { CustomTooltipsLabelProvider, CustomTooltipsProvider } from './components/custom-tooltips-prop';
|
||||
import { LoadMvsData, MVSJFormatProvider } from './components/formats';
|
||||
import { IsMVSModelProvider } from './components/is-mvs-model-prop';
|
||||
import { makeMultilayerColorThemeProvider } from './components/multilayer-color-theme';
|
||||
import { loadMVS } from './load';
|
||||
import { MVSData } from './mvs-data';
|
||||
@@ -51,6 +52,7 @@ export const MolViewSpec = PluginBehavior.create<{ autoAttach: boolean }>({
|
||||
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
|
||||
private readonly registrables: Registrables = {
|
||||
customModelProperties: [
|
||||
IsMVSModelProvider,
|
||||
MVSAnnotationsProvider,
|
||||
],
|
||||
customStructureProperties: [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
@@ -12,6 +12,7 @@ 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" */
|
||||
@@ -76,5 +77,5 @@ export const MVSAnnotationColorThemeProvider: ColorTheme.Provider<MVSAnnotationC
|
||||
factory: MVSAnnotationColorTheme,
|
||||
getParams: ctx => MVSAnnotationColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(MVSAnnotationColorThemeParams),
|
||||
isApplicable: (ctx: ThemeDataContext) => true,
|
||||
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && isMVSStructure(ctx.structure),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
@@ -9,6 +9,7 @@ import { Representation, RepresentationContext, RepresentationParamsGetter } fro
|
||||
import { ComplexRepresentation, StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../../../../mol-repr/structure/representation';
|
||||
import { MarkerAction } from '../../../../mol-util/marker-action';
|
||||
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
|
||||
import { isMVSStructure } from '../is-mvs-model-prop';
|
||||
import { MVSAnnotationLabelTextParams, MVSAnnotationLabelTextVisual } from './visual';
|
||||
|
||||
|
||||
@@ -45,5 +46,5 @@ export const MVSAnnotationLabelRepresentationProvider = StructureRepresentationP
|
||||
defaultValues: PD.getDefaultValues(MVSAnnotationLabelParams),
|
||||
defaultColorTheme: { name: 'uniform' }, // this ain't workin
|
||||
defaultSizeTheme: { name: 'physical' },
|
||||
isApplicable: (structure: Structure) => structure.elementCount > 0,
|
||||
isApplicable: (structure: Structure) => structure.elementCount > 0 && isMVSStructure(structure),
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
@@ -75,7 +75,7 @@ type MVSAnnotationData = { format: 'json', data: Jsonable } | { format: 'cif', d
|
||||
|
||||
/** Provider for custom model property "Annotations" */
|
||||
export const MVSAnnotationsProvider: CustomModelProperty.Provider<MVSAnnotationsParams, MVSAnnotations> = CustomModelProperty.createProvider({
|
||||
label: 'Annotations',
|
||||
label: 'MVS Annotations',
|
||||
descriptor: CustomPropertyDescriptor({
|
||||
name: 'mvs-annotations',
|
||||
}),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
@@ -9,6 +9,7 @@ import { Representation, RepresentationContext, RepresentationParamsGetter } fro
|
||||
import { ComplexRepresentation, StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../../../../mol-repr/structure/representation';
|
||||
import { MarkerAction } from '../../../../mol-util/marker-action';
|
||||
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
|
||||
import { isMVSStructure } from '../is-mvs-model-prop';
|
||||
import { CustomLabelTextParams, CustomLabelTextVisual } from './visual';
|
||||
|
||||
|
||||
@@ -38,12 +39,12 @@ export function CustomLabelRepresentation(ctx: RepresentationContext, getParams:
|
||||
/** A thingy that is needed to register representation type "Custom Label", allowing user-defined labels at at user-defined positions */
|
||||
export const CustomLabelRepresentationProvider = StructureRepresentationProvider({
|
||||
name: 'mvs-custom-label',
|
||||
label: 'Custom Label',
|
||||
label: 'MVS Custom Label',
|
||||
description: 'Displays labels with custom text',
|
||||
factory: CustomLabelRepresentation,
|
||||
getParams: () => CustomLabelParams,
|
||||
defaultValues: PD.getDefaultValues(CustomLabelParams),
|
||||
defaultColorTheme: { name: 'uniform' },
|
||||
defaultSizeTheme: { name: 'physical' },
|
||||
isApplicable: (structure: Structure) => structure.elementCount > 0
|
||||
isApplicable: (structure: Structure) => structure.elementCount > 0 && isMVSStructure(structure),
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
@@ -36,7 +36,7 @@ export type CustomTooltipsData = { selector: Selector, text: string, elementSet?
|
||||
|
||||
/** Provider for custom structure property "CustomTooltips" */
|
||||
export const CustomTooltipsProvider: CustomStructureProperty.Provider<CustomTooltipsParams, CustomTooltipsData> = CustomStructureProperty.createProvider({
|
||||
label: 'Custom Tooltips',
|
||||
label: 'MVS Custom Tooltips',
|
||||
descriptor: CustomPropertyDescriptor<any, any>({
|
||||
name: 'mvs-custom-tooltips',
|
||||
}),
|
||||
|
||||
43
src/extensions/mvs/components/is-mvs-model-prop.ts
Normal file
43
src/extensions/mvs/components/is-mvs-model-prop.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
|
||||
import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property';
|
||||
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
|
||||
import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
|
||||
import { Model, Structure } from '../../../mol-model/structure';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
|
||||
|
||||
/** Parameter definition for custom model property "Is MVS" */
|
||||
export type IsMVSModelParams = typeof IsMVSModelParams
|
||||
export const IsMVSModelParams = {
|
||||
isMvs: PD.Boolean(false, { description: 'Flag this model as managed by MolViewSpec and enable MolViewSpec features' }),
|
||||
};
|
||||
|
||||
/** Parameter values for custom model property "Is MVS" */
|
||||
export type IsMVSModelProps = PD.Values<IsMVSModelParams>
|
||||
|
||||
/** Provider for custom model property "Is MVS" */
|
||||
export const IsMVSModelProvider: CustomModelProperty.Provider<IsMVSModelParams, {}> = CustomModelProperty.createProvider({
|
||||
label: 'MVS',
|
||||
descriptor: CustomPropertyDescriptor({
|
||||
name: 'mvs-is-mvs-model',
|
||||
}),
|
||||
type: 'static',
|
||||
defaultParams: IsMVSModelParams,
|
||||
getParams: (data: Model) => IsMVSModelParams,
|
||||
isApplicable: (data: Model) => true,
|
||||
obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<IsMVSModelProps>) => ({ value: {} }),
|
||||
});
|
||||
|
||||
/** Decide if the model is flagged as managed by MolViewSpec */
|
||||
export function isMVSModel(model: Model): boolean {
|
||||
return !!IsMVSModelProvider.props(model)?.isMvs;
|
||||
}
|
||||
/** Decide if the structure is flagged as managed by MolViewSpec */
|
||||
export function isMVSStructure(structure: Structure): boolean {
|
||||
return structure.models.some(isMVSModel);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
@@ -12,6 +12,7 @@ import { Color } from '../../../mol-util/color';
|
||||
import { ColorNames } from '../../../mol-util/color/names';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { stringToWords } from '../../../mol-util/string';
|
||||
import { isMVSStructure } from './is-mvs-model-prop';
|
||||
import { ElementSet, SelectorParams, isSelectorAll } from './selector';
|
||||
|
||||
|
||||
@@ -137,11 +138,11 @@ export const MultilayerColorThemeName = 'mvs-multilayer';
|
||||
export function makeMultilayerColorThemeProvider(colorThemeRegistry: ColorTheme.Registry): ColorTheme.Provider<MultilayerColorThemeParams, typeof MultilayerColorThemeName> {
|
||||
return {
|
||||
name: MultilayerColorThemeName,
|
||||
label: 'Multi-layer',
|
||||
label: 'MVS Multi-layer',
|
||||
category: ColorTheme.Category.Misc,
|
||||
factory: (ctx, props) => makeMultilayerColorTheme(ctx, props, colorThemeRegistry),
|
||||
getParams: (ctx: ThemeDataContext) => makeMultilayerColorThemeParams(colorThemeRegistry, ctx),
|
||||
defaultValues: DefaultMultilayerColorThemeProps,
|
||||
isApplicable: (ctx: ThemeDataContext) => true,
|
||||
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && isMVSStructure(ctx.structure),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
@@ -16,6 +16,7 @@ import { MVSAnnotationStructureComponent } from './components/annotation-structu
|
||||
import { MVSAnnotationTooltipsProvider } from './components/annotation-tooltips-prop';
|
||||
import { CustomLabelProps, CustomLabelRepresentationProvider } from './components/custom-label/representation';
|
||||
import { CustomTooltipsProvider } from './components/custom-tooltips-prop';
|
||||
import { IsMVSModelProps, IsMVSModelProvider } from './components/is-mvs-model-prop';
|
||||
import { AnnotationFromSourceKind, AnnotationFromUriKind, LoadingActions, UpdateTarget, collectAnnotationReferences, collectAnnotationTooltips, collectInlineLabels, collectInlineTooltips, colorThemeForNode, componentFromXProps, componentPropsFromSelector, isPhantomComponent, labelFromXProps, loadTree, makeNearestReprMap, prettyNameFromSelector, representationProps, structureProps, transformProps } from './load-helpers';
|
||||
import { MVSData } from './mvs-data';
|
||||
import { ParamsOfKind, SubTreeOfKind, validateTree } from './tree/generic/tree-schema';
|
||||
@@ -119,10 +120,12 @@ const MolstarLoadingActions: LoadingActions<MolstarTree, MolstarLoadingContext>
|
||||
});
|
||||
UpdateTarget.apply(model, CustomModelProperties, {
|
||||
properties: {
|
||||
[MVSAnnotationsProvider.descriptor.name]: { annotations }
|
||||
[IsMVSModelProvider.descriptor.name]: { isMvs: true } satisfies IsMVSModelProps,
|
||||
[MVSAnnotationsProvider.descriptor.name]: { annotations },
|
||||
},
|
||||
autoAttach: [
|
||||
MVSAnnotationsProvider.descriptor.name
|
||||
IsMVSModelProvider.descriptor.name,
|
||||
MVSAnnotationsProvider.descriptor.name,
|
||||
],
|
||||
});
|
||||
return model;
|
||||
|
||||
@@ -6,7 +6,7 @@ export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?:
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
|
||||
export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
|
||||
export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
|
||||
// Generated on 2023-12-02T13:19:10-08:00
|
||||
// Generated on 2024-02-03T09:57:34-08:00
|
||||
|
||||
/** All built-in and custom scalars, mapped to their actual values */
|
||||
export type Scalars = {
|
||||
@@ -496,7 +496,9 @@ export type CoreAssembly = {
|
||||
readonly pdbx_struct_oper_list?: Maybe<ReadonlyArray<Maybe<PdbxStructOperList>>>;
|
||||
/** Get a list of polymer entity instances (chains) that constitute this assembly. */
|
||||
readonly polymer_entity_instances?: Maybe<ReadonlyArray<Maybe<CorePolymerEntityInstance>>>;
|
||||
readonly rcsb_assembly_annotation?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyAnnotation>>>;
|
||||
readonly rcsb_assembly_container_identifiers: RcsbAssemblyContainerIdentifiers;
|
||||
readonly rcsb_assembly_feature?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyFeature>>>;
|
||||
readonly rcsb_assembly_info?: Maybe<RcsbAssemblyInfo>;
|
||||
/**
|
||||
* A unique identifier for each object in this assembly container formed by
|
||||
@@ -1223,8 +1225,15 @@ export type DrugbankInfo = {
|
||||
readonly description?: Maybe<Scalars['String']['output']>;
|
||||
/** The DrugBank drug categories. */
|
||||
readonly drug_categories?: Maybe<ReadonlyArray<Maybe<Scalars['String']['output']>>>;
|
||||
/** The DrugBank drug drug groups. */
|
||||
/**
|
||||
* The DrugBank drug groups determine their drug development status.
|
||||
*
|
||||
* Allowable values:
|
||||
* approved, experimental, illicit, investigational, nutraceutical, vet_approved, withdrawn
|
||||
*
|
||||
*/
|
||||
readonly drug_groups?: Maybe<ReadonlyArray<Maybe<Scalars['String']['output']>>>;
|
||||
readonly drug_products?: Maybe<ReadonlyArray<Maybe<DrugbankInfoDrugProducts>>>;
|
||||
/** The DrugBank accession code */
|
||||
readonly drugbank_id: Scalars['String']['output'];
|
||||
/**
|
||||
@@ -1257,6 +1266,57 @@ export type DrugbankInfo = {
|
||||
readonly synonyms?: Maybe<ReadonlyArray<Maybe<Scalars['String']['output']>>>;
|
||||
};
|
||||
|
||||
export type DrugbankInfoDrugProducts = {
|
||||
/**
|
||||
* Indicates whether this drug has been approved by the regulating government.
|
||||
*
|
||||
* Allowable values:
|
||||
* N, Y
|
||||
*
|
||||
*/
|
||||
readonly approved?: Maybe<Scalars['String']['output']>;
|
||||
/**
|
||||
* The country where this commercially available drug has been approved.
|
||||
*
|
||||
* Allowable values:
|
||||
* Canada, EU, US
|
||||
*
|
||||
*/
|
||||
readonly country?: Maybe<Scalars['String']['output']>;
|
||||
/**
|
||||
* The ending date for market approval.
|
||||
*
|
||||
* Examples:
|
||||
* 2003-07-30
|
||||
*
|
||||
*/
|
||||
readonly ended_marketing_on?: Maybe<Scalars['Date']['output']>;
|
||||
/**
|
||||
* The proprietary name(s) provided by the manufacturer for any commercially available products containing this drug.
|
||||
*
|
||||
* Examples:
|
||||
* Hivid Tab 0.375mg
|
||||
*
|
||||
*/
|
||||
readonly name?: Maybe<Scalars['String']['output']>;
|
||||
/**
|
||||
* Source of this product information. For example, a value of DPD indicates this information was retrieved from the Canadian Drug Product Database.
|
||||
*
|
||||
* Allowable values:
|
||||
* DPD, EMA, FDA NDC
|
||||
*
|
||||
*/
|
||||
readonly source?: Maybe<Scalars['String']['output']>;
|
||||
/**
|
||||
* The starting date for market approval.
|
||||
*
|
||||
* Examples:
|
||||
* 1992-12-31
|
||||
*
|
||||
*/
|
||||
readonly started_marketing_on?: Maybe<Scalars['Date']['output']>;
|
||||
};
|
||||
|
||||
export type DrugbankTarget = {
|
||||
/** The type of target interaction. */
|
||||
readonly interaction_type?: Maybe<Scalars['String']['output']>;
|
||||
@@ -6591,6 +6651,48 @@ export type RcsbAccessionInfo = {
|
||||
readonly status_code?: Maybe<Scalars['String']['output']>;
|
||||
};
|
||||
|
||||
export type RcsbAssemblyAnnotation = {
|
||||
readonly additional_properties?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyAnnotationAdditionalProperties>>>;
|
||||
/** An identifier for the annotation. */
|
||||
readonly annotation_id?: Maybe<Scalars['String']['output']>;
|
||||
/** Identifies the version of the annotation assignment. */
|
||||
readonly assignment_version?: Maybe<Scalars['String']['output']>;
|
||||
/** A description for the annotation. */
|
||||
readonly description?: Maybe<Scalars['String']['output']>;
|
||||
/** A name for the annotation. */
|
||||
readonly name?: Maybe<Scalars['String']['output']>;
|
||||
/**
|
||||
* Code identifying the individual, organization or program that
|
||||
* assigned the annotation.
|
||||
*
|
||||
* Examples:
|
||||
* MCSA
|
||||
*
|
||||
*/
|
||||
readonly provenance_source?: Maybe<Scalars['String']['output']>;
|
||||
/**
|
||||
* A type or category of the annotation.
|
||||
*
|
||||
* Allowable values:
|
||||
* MCSA
|
||||
*
|
||||
*/
|
||||
readonly type?: Maybe<Scalars['String']['output']>;
|
||||
};
|
||||
|
||||
export type RcsbAssemblyAnnotationAdditionalProperties = {
|
||||
/**
|
||||
* The additional property name.
|
||||
*
|
||||
* Allowable values:
|
||||
* MCSA_MOTIF_COMPATIBILITY
|
||||
*
|
||||
*/
|
||||
readonly name?: Maybe<Scalars['String']['output']>;
|
||||
/** The value(s) of the additional property. */
|
||||
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['ObjectScalar']['output']>>>;
|
||||
};
|
||||
|
||||
export type RcsbAssemblyContainerIdentifiers = {
|
||||
/**
|
||||
* Assembly identifier for the container.
|
||||
@@ -6615,6 +6717,69 @@ export type RcsbAssemblyContainerIdentifiers = {
|
||||
readonly rcsb_id?: Maybe<Scalars['String']['output']>;
|
||||
};
|
||||
|
||||
export type RcsbAssemblyFeature = {
|
||||
readonly additional_properties?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyFeatureAdditionalProperties>>>;
|
||||
/** Identifies the version of the feature assignment. */
|
||||
readonly assignment_version?: Maybe<Scalars['String']['output']>;
|
||||
/** A description for the feature. */
|
||||
readonly description?: Maybe<Scalars['String']['output']>;
|
||||
/** An identifier for the feature. */
|
||||
readonly feature_id?: Maybe<Scalars['String']['output']>;
|
||||
/** This container groups together chain-level identifiers of the assigned features. */
|
||||
readonly feature_positions?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyFeatureFeaturePositions>>>;
|
||||
/** A name for the feature. */
|
||||
readonly name?: Maybe<Scalars['String']['output']>;
|
||||
/**
|
||||
* Code identifying the individual, organization or program that
|
||||
* assigned the feature.
|
||||
*
|
||||
* Examples:
|
||||
* MCSA
|
||||
*
|
||||
*/
|
||||
readonly provenance_source?: Maybe<Scalars['String']['output']>;
|
||||
/**
|
||||
* A type or category of the feature.
|
||||
*
|
||||
* Allowable values:
|
||||
* MCSA
|
||||
*
|
||||
*/
|
||||
readonly type?: Maybe<Scalars['String']['output']>;
|
||||
};
|
||||
|
||||
export type RcsbAssemblyFeatureAdditionalProperties = {
|
||||
/**
|
||||
* The additional property name.
|
||||
*
|
||||
* Allowable values:
|
||||
* MCSA_MOTIF_COMPATIBILITY
|
||||
*
|
||||
*/
|
||||
readonly name?: Maybe<Scalars['String']['output']>;
|
||||
/** The value(s) of the additional property. */
|
||||
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['ObjectScalar']['output']>>>;
|
||||
};
|
||||
|
||||
export type RcsbAssemblyFeatureFeaturePositions = {
|
||||
/**
|
||||
* An identifier of polymer chain (label_asym_id) corresponding to the feature assignment.
|
||||
*
|
||||
* Examples:
|
||||
* A, B
|
||||
*
|
||||
*/
|
||||
readonly asym_id: Scalars['String']['output'];
|
||||
/** An identifier for the monomer at which this segment of the feature begins. */
|
||||
readonly beg_seq_id: Scalars['Int']['output'];
|
||||
/** An identifier for the monomer at which this segment of the feature ends. */
|
||||
readonly end_seq_id?: Maybe<Scalars['Int']['output']>;
|
||||
/** Identifies the list of operations from the category pdbx_struct_oper_list. One item in array per operator applied. The order follows how operators are applied. */
|
||||
readonly struct_oper_list: ReadonlyArray<Maybe<Scalars['String']['output']>>;
|
||||
/** The value(s) of the feature over the monomer segment. */
|
||||
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['Float']['output']>>>;
|
||||
};
|
||||
|
||||
export type RcsbAssemblyInfo = {
|
||||
/** Entity identifier for the container. */
|
||||
readonly assembly_id?: Maybe<Scalars['String']['output']>;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { ValueCell } from '../../mol-util';
|
||||
@@ -155,25 +156,29 @@ function createInstanceColor(locationIt: LocationIterator, color: LocationColor,
|
||||
|
||||
/** Creates color texture with color for each group (i.e. shared across instances) */
|
||||
function createGroupColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
|
||||
const { groupCount } = locationIt;
|
||||
const colors = createTextureImage(Math.max(1, groupCount), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
|
||||
const { groupCount, hasLocation2 } = locationIt;
|
||||
const colors = createTextureImage(Math.max(1, groupCount * (hasLocation2 ? 2 : 1)), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
|
||||
locationIt.reset();
|
||||
const indexMultiplier = hasLocation2 ? 6 : 3;
|
||||
while (locationIt.hasNext && !locationIt.isNextNewInstance) {
|
||||
const { location, isSecondary, groupIndex } = locationIt.move();
|
||||
Color.toArray(color(location, isSecondary), colors.array, groupIndex * 3);
|
||||
const { location, location2, isSecondary, groupIndex } = locationIt.move();
|
||||
Color.toArray(color(location, isSecondary), colors.array, groupIndex * indexMultiplier);
|
||||
if (hasLocation2) Color.toArray(color(location2, isSecondary), colors.array, groupIndex * indexMultiplier + 3);
|
||||
}
|
||||
return createTextureColor(colors, 'group', colorData);
|
||||
}
|
||||
|
||||
/** Creates color texture with color for each group in each instance */
|
||||
function createGroupInstanceColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
|
||||
const { groupCount, instanceCount } = locationIt;
|
||||
const count = instanceCount * groupCount;
|
||||
const { groupCount, instanceCount, hasLocation2 } = locationIt;
|
||||
const count = instanceCount * groupCount * (hasLocation2 ? 2 : 1);
|
||||
const colors = createTextureImage(Math.max(1, count), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
|
||||
locationIt.reset();
|
||||
const indexMultiplier = hasLocation2 ? 6 : 3;
|
||||
while (locationIt.hasNext) {
|
||||
const { location, isSecondary, index } = locationIt.move();
|
||||
Color.toArray(color(location, isSecondary), colors.array, index * 3);
|
||||
const { location, location2, isSecondary, index } = locationIt.move();
|
||||
Color.toArray(color(location, isSecondary), colors.array, index * indexMultiplier);
|
||||
if (hasLocation2) Color.toArray(color(location2, isSecondary), colors.array, index * indexMultiplier + 3);
|
||||
}
|
||||
return createTextureColor(colors, 'groupInstance', colorData);
|
||||
}
|
||||
@@ -258,4 +263,4 @@ function createDirectColor(colorData?: ColorData): ColorData {
|
||||
dUsePalette: ValueCell.create(false),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,15 @@ import { Cylinders } from './cylinders';
|
||||
import { Vec3 } from '../../../mol-math/linear-algebra';
|
||||
|
||||
export interface CylindersBuilder {
|
||||
add(startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, radiusScale: number, topCap: boolean, bottomCap: boolean, group: number): void
|
||||
addFixedCountDashes(start: Vec3, end: Vec3, segmentCount: number, radiusScale: number, topCap: boolean, bottomCap: boolean, stubCap: boolean, group: number): void
|
||||
addFixedLengthDashes(start: Vec3, end: Vec3, segmentLength: number, radiusScale: number, topCap: boolean, bottomCap: boolean, group: number): void
|
||||
/**
|
||||
* @param colorMode - controls if and how theme colors are interpolated
|
||||
* - for colorMode between 0 and 1 use colorMode to interpolate
|
||||
* - for colorMode == 2 do nothing, i.e., use given theme color
|
||||
* - for colorMode == 3 use position on cylinder axis to interpolate
|
||||
*/
|
||||
add(startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, radiusScale: number, topCap: boolean, bottomCap: boolean, colorMode: number, group: number): void
|
||||
addFixedCountDashes(start: Vec3, end: Vec3, segmentCount: number, radiusScale: number, topCap: boolean, bottomCap: boolean, stubCap: boolean, interpolate: boolean, group: number): void
|
||||
addFixedLengthDashes(start: Vec3, end: Vec3, segmentLength: number, radiusScale: number, topCap: boolean, bottomCap: boolean, interpolate: boolean, group: number): void
|
||||
getCylinders(): Cylinders
|
||||
}
|
||||
|
||||
@@ -31,22 +37,25 @@ export namespace CylindersBuilder {
|
||||
const ends = ChunkedArray.create(Float32Array, 3, chunkSize, cylinders ? cylinders.endBuffer.ref.value : initialCount);
|
||||
const scales = ChunkedArray.create(Float32Array, 1, chunkSize, cylinders ? cylinders.scaleBuffer.ref.value : initialCount);
|
||||
const caps = ChunkedArray.create(Float32Array, 1, chunkSize, cylinders ? cylinders.capBuffer.ref.value : initialCount);
|
||||
const colorModes = ChunkedArray.create(Float32Array, 1, chunkSize, cylinders ? cylinders.colorModeBuffer.ref.value : initialCount);
|
||||
|
||||
const add = (startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, radiusScale: number, topCap: boolean, bottomCap: boolean, group: number) => {
|
||||
const add = (startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, radiusScale: number, topCap: boolean, bottomCap: boolean, colorMode: number, group: number) => {
|
||||
for (let i = 0; i < 6; ++i) {
|
||||
caAdd3(starts, startX, startY, startZ);
|
||||
caAdd3(ends, endX, endY, endZ);
|
||||
caAdd(groups, group);
|
||||
caAdd(scales, radiusScale);
|
||||
caAdd(caps, (topCap ? 1 : 0) + (bottomCap ? 2 : 0));
|
||||
caAdd(colorModes, colorMode);
|
||||
}
|
||||
};
|
||||
|
||||
const addFixedCountDashes = (start: Vec3, end: Vec3, segmentCount: number, radiusScale: number, topCap: boolean, bottomCap: boolean, stubCap: boolean, group: number) => {
|
||||
const addFixedCountDashes = (start: Vec3, end: Vec3, segmentCount: number, radiusScale: number, topCap: boolean, bottomCap: boolean, stubCap: boolean, interpolate: boolean, group: number) => {
|
||||
const d = Vec3.distance(start, end);
|
||||
const isOdd = segmentCount % 2 !== 0;
|
||||
const s = Math.floor((segmentCount + 1) / 2);
|
||||
const step = d / (segmentCount + 0.5);
|
||||
let colorMode = 2.0;
|
||||
|
||||
Vec3.setMagnitude(tmpDir, Vec3.sub(tmpDir, end, start), step);
|
||||
Vec3.copy(tmpVecA, start);
|
||||
@@ -58,7 +67,10 @@ export namespace CylindersBuilder {
|
||||
} else {
|
||||
Vec3.add(tmpVecB, tmpVecA, tmpDir);
|
||||
}
|
||||
add(tmpVecA[0], tmpVecA[1], tmpVecA[2], tmpVecB[0], tmpVecB[1], tmpVecB[2], radiusScale, topCap, bottomCap, group);
|
||||
if (interpolate) {
|
||||
colorMode = Vec3.distance(start, tmpVecB) / (d * 2);
|
||||
}
|
||||
add(tmpVecA[0], tmpVecA[1], tmpVecA[2], tmpVecB[0], tmpVecB[1], tmpVecB[2], radiusScale, topCap, bottomCap, colorMode, group);
|
||||
Vec3.add(tmpVecA, tmpVecA, tmpDir);
|
||||
}
|
||||
};
|
||||
@@ -66,9 +78,9 @@ export namespace CylindersBuilder {
|
||||
return {
|
||||
add,
|
||||
addFixedCountDashes,
|
||||
addFixedLengthDashes: (start: Vec3, end: Vec3, segmentLength: number, radiusScale: number, topCap: boolean, bottomCap: boolean, group: number) => {
|
||||
addFixedLengthDashes: (start: Vec3, end: Vec3, segmentLength: number, radiusScale: number, topCap: boolean, bottomCap: boolean, interpolate: boolean, group: number) => {
|
||||
const d = Vec3.distance(start, end);
|
||||
addFixedCountDashes(start, end, d / segmentLength, radiusScale, topCap, bottomCap, true, group);
|
||||
addFixedCountDashes(start, end, d / segmentLength, radiusScale, topCap, bottomCap, true, interpolate, group);
|
||||
},
|
||||
getCylinders: () => {
|
||||
const cylinderCount = groups.elementCount / 6;
|
||||
@@ -77,10 +89,11 @@ export namespace CylindersBuilder {
|
||||
const eb = ChunkedArray.compact(ends, true) as Float32Array;
|
||||
const ab = ChunkedArray.compact(scales, true) as Float32Array;
|
||||
const cb = ChunkedArray.compact(caps, true) as Float32Array;
|
||||
const cmb = ChunkedArray.compact(colorModes, true) as Float32Array;
|
||||
const mb = cylinders && cylinderCount <= cylinders.cylinderCount ? cylinders.mappingBuffer.ref.value : new Float32Array(cylinderCount * 18);
|
||||
const ib = cylinders && cylinderCount <= cylinders.cylinderCount ? cylinders.indexBuffer.ref.value : new Uint32Array(cylinderCount * 12);
|
||||
if (!cylinders || cylinderCount > cylinders.cylinderCount) fillMappingAndIndices(cylinderCount, mb, ib);
|
||||
return Cylinders.create(mb, ib, gb, sb, eb, ab, cb, cylinderCount, cylinders);
|
||||
return Cylinders.create(mb, ib, gb, sb, eb, ab, cb, cmb, cylinderCount, cylinders);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
@@ -47,6 +48,13 @@ export interface Cylinders {
|
||||
readonly scaleBuffer: ValueCell<Float32Array>,
|
||||
/** Cylinder cap buffer as array of cap flags wrapped in a value cell */
|
||||
readonly capBuffer: ValueCell<Float32Array>,
|
||||
/**
|
||||
* Cylinder colorMode buffer as array of coloring modes flags wrapped in a value cell
|
||||
* - for colorMode between 0 and 1 use colorMode to interpolate
|
||||
* - for colorMode == 2 do nothing, i.e., use given theme color
|
||||
* - for colorMode == 3 use position on cylinder axis to interpolate
|
||||
*/
|
||||
readonly colorModeBuffer: ValueCell<Float32Array>,
|
||||
|
||||
/** Bounding sphere of the cylinders */
|
||||
readonly boundingSphere: Sphere3D
|
||||
@@ -57,10 +65,10 @@ export interface Cylinders {
|
||||
}
|
||||
|
||||
export namespace Cylinders {
|
||||
export function create(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, cylinderCount: number, cylinders?: Cylinders): Cylinders {
|
||||
export function create(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, colorModes: Float32Array, cylinderCount: number, cylinders?: Cylinders): Cylinders {
|
||||
return cylinders ?
|
||||
update(mappings, indices, groups, starts, ends, scales, caps, cylinderCount, cylinders) :
|
||||
fromArrays(mappings, indices, groups, starts, ends, scales, caps, cylinderCount);
|
||||
update(mappings, indices, groups, starts, ends, scales, caps, colorModes, cylinderCount, cylinders) :
|
||||
fromArrays(mappings, indices, groups, starts, ends, scales, caps, colorModes, cylinderCount);
|
||||
}
|
||||
|
||||
export function createEmpty(cylinders?: Cylinders): Cylinders {
|
||||
@@ -71,17 +79,18 @@ export namespace Cylinders {
|
||||
const eb = cylinders ? cylinders.endBuffer.ref.value : new Float32Array(0);
|
||||
const ab = cylinders ? cylinders.scaleBuffer.ref.value : new Float32Array(0);
|
||||
const cb = cylinders ? cylinders.capBuffer.ref.value : new Float32Array(0);
|
||||
return create(mb, ib, gb, sb, eb, ab, cb, 0, cylinders);
|
||||
const cmb = cylinders ? cylinders.colorModeBuffer.ref.value : new Float32Array(0);
|
||||
return create(mb, ib, gb, sb, eb, ab, cb, cmb, 0, cylinders);
|
||||
}
|
||||
|
||||
function hashCode(cylinders: Cylinders) {
|
||||
return hashFnv32a([
|
||||
cylinders.cylinderCount, cylinders.mappingBuffer.ref.version, cylinders.indexBuffer.ref.version,
|
||||
cylinders.groupBuffer.ref.version, cylinders.startBuffer.ref.version, cylinders.endBuffer.ref.version, cylinders.scaleBuffer.ref.version, cylinders.capBuffer.ref.version
|
||||
cylinders.groupBuffer.ref.version, cylinders.startBuffer.ref.version, cylinders.endBuffer.ref.version, cylinders.scaleBuffer.ref.version, cylinders.capBuffer.ref.version, cylinders.colorModeBuffer.ref.version
|
||||
]);
|
||||
}
|
||||
|
||||
function fromArrays(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, cylinderCount: number): Cylinders {
|
||||
function fromArrays(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, colorModes: Float32Array, cylinderCount: number): Cylinders {
|
||||
|
||||
const boundingSphere = Sphere3D();
|
||||
let groupMapping: GroupMapping;
|
||||
@@ -99,6 +108,7 @@ export namespace Cylinders {
|
||||
endBuffer: ValueCell.create(ends),
|
||||
scaleBuffer: ValueCell.create(scales),
|
||||
capBuffer: ValueCell.create(caps),
|
||||
colorModeBuffer: ValueCell.create(colorModes),
|
||||
get boundingSphere() {
|
||||
const newHash = hashCode(cylinders);
|
||||
if (newHash !== currentHash) {
|
||||
@@ -125,7 +135,7 @@ export namespace Cylinders {
|
||||
return cylinders;
|
||||
}
|
||||
|
||||
function update(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, cylinderCount: number, cylinders: Cylinders) {
|
||||
function update(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, colorModes: Float32Array, cylinderCount: number, cylinders: Cylinders) {
|
||||
if (cylinderCount > cylinders.cylinderCount) {
|
||||
ValueCell.update(cylinders.mappingBuffer, mappings);
|
||||
ValueCell.update(cylinders.indexBuffer, indices);
|
||||
@@ -136,6 +146,7 @@ export namespace Cylinders {
|
||||
ValueCell.update(cylinders.endBuffer, ends);
|
||||
ValueCell.update(cylinders.scaleBuffer, scales);
|
||||
ValueCell.update(cylinders.capBuffer, caps);
|
||||
ValueCell.update(cylinders.colorModeBuffer, colorModes);
|
||||
return cylinders;
|
||||
}
|
||||
|
||||
@@ -157,10 +168,11 @@ export namespace Cylinders {
|
||||
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Select<boolean | 'inverted'>(false, [[false, 'Off'], [true, 'On'], ['inverted', 'Inverted']], BaseGeometry.ShadingCategory),
|
||||
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
|
||||
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory),
|
||||
solidInterior: PD.Boolean(true, BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
colorMode: PD.Select('default', PD.arrayToOptions(['default', 'interpolate'] as const), BaseGeometry.ShadingCategory)
|
||||
};
|
||||
export type Params = typeof Params
|
||||
|
||||
@@ -215,7 +227,6 @@ export namespace Cylinders {
|
||||
const padding = getMaxSize(size) * props.sizeFactor;
|
||||
const invariantBoundingSphere = Sphere3D.clone(cylinders.boundingSphere);
|
||||
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
|
||||
|
||||
return {
|
||||
dGeometryType: ValueCell.create('cylinders'),
|
||||
|
||||
@@ -225,6 +236,7 @@ export namespace Cylinders {
|
||||
aEnd: cylinders.endBuffer,
|
||||
aScale: cylinders.scaleBuffer,
|
||||
aCap: cylinders.capBuffer,
|
||||
aColorMode: cylinders.colorModeBuffer,
|
||||
elements: cylinders.indexBuffer,
|
||||
boundingSphere: ValueCell.create(boundingSphere),
|
||||
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
|
||||
@@ -249,6 +261,7 @@ export namespace Cylinders {
|
||||
dSolidInterior: ValueCell.create(props.solidInterior),
|
||||
uBumpFrequency: ValueCell.create(props.bumpFrequency),
|
||||
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
|
||||
dDualColor: ValueCell.create(props.colorMode === 'interpolate'),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -268,6 +281,7 @@ export namespace Cylinders {
|
||||
ValueCell.updateIfChanged(values.dSolidInterior, props.solidInterior);
|
||||
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
|
||||
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
|
||||
ValueCell.updateIfChanged(values.dDualColor, props.colorMode === 'interpolate');
|
||||
}
|
||||
|
||||
function updateBoundingSphere(values: CylindersValues, cylinders: Cylinders) {
|
||||
@@ -294,4 +308,4 @@ export namespace Cylinders {
|
||||
state.opaque = state.opaque && !props.xrayShaded;
|
||||
state.writeDepth = state.opaque;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,7 +628,7 @@ export namespace Mesh {
|
||||
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Select<boolean | 'inverted'>(false, [[false, 'Off'], [true, 'On'], ['inverted', 'Inverted']], BaseGeometry.ShadingCategory),
|
||||
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
|
||||
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
|
||||
@@ -148,7 +148,7 @@ export namespace Spheres {
|
||||
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Select<boolean | 'inverted'>(false, [[false, 'Off'], [true, 'On'], ['inverted', 'Inverted']], BaseGeometry.ShadingCategory),
|
||||
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
|
||||
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory),
|
||||
solidInterior: PD.Boolean(true, BaseGeometry.ShadingCategory),
|
||||
clipPrimitive: PD.Boolean(false, { ...BaseGeometry.ShadingCategory, description: 'Clip whole sphere instead of cutting it.' }),
|
||||
approximate: PD.Boolean(false, { ...BaseGeometry.ShadingCategory, description: 'Faster rendering, but has artifacts.' }),
|
||||
|
||||
@@ -120,7 +120,7 @@ export namespace TextureMesh {
|
||||
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
|
||||
xrayShaded: PD.Select<boolean | 'inverted'>(false, [[false, 'Off'], [true, 'On'], ['inverted', 'Inverted']], BaseGeometry.ShadingCategory),
|
||||
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
|
||||
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { Iterator } from '../../mol-data';
|
||||
@@ -10,6 +11,7 @@ import { NullLocation, Location } from '../../mol-model/location';
|
||||
|
||||
export interface LocationValue {
|
||||
location: Location
|
||||
location2: Location
|
||||
index: number
|
||||
groupIndex: number
|
||||
instanceIndex: number
|
||||
@@ -24,6 +26,7 @@ export interface LocationIterator extends Iterator<LocationValue> {
|
||||
readonly count: number
|
||||
readonly stride: number
|
||||
readonly nonInstanceable: boolean
|
||||
readonly hasLocation2: boolean
|
||||
move(): LocationValue
|
||||
reset(): void
|
||||
skipInstance(): void
|
||||
@@ -33,13 +36,14 @@ export interface LocationIterator extends Iterator<LocationValue> {
|
||||
type LocationGetter = (groupIndex: number, instanceIndex: number) => Location
|
||||
type IsSecondaryGetter = (groupIndex: number, instanceIndex: number) => boolean
|
||||
|
||||
export function LocationIterator(groupCount: number, instanceCount: number, stride: number, getLocation: LocationGetter, nonInstanceable = false, isSecondary: IsSecondaryGetter = () => false): LocationIterator {
|
||||
export function LocationIterator(groupCount: number, instanceCount: number, stride: number, getLocation: LocationGetter, nonInstanceable = false, isSecondary: IsSecondaryGetter = () => false, getLocation2?: LocationGetter): LocationIterator {
|
||||
if (groupCount % stride !== 0) {
|
||||
throw new Error('incompatible groupCount and stride');
|
||||
}
|
||||
|
||||
const value: LocationValue = {
|
||||
location: NullLocation as Location,
|
||||
location2: NullLocation as Location,
|
||||
index: 0,
|
||||
groupIndex: 0,
|
||||
instanceIndex: 0,
|
||||
@@ -52,6 +56,8 @@ export function LocationIterator(groupCount: number, instanceCount: number, stri
|
||||
let instanceIndex = 0;
|
||||
let voidInstances = false;
|
||||
|
||||
const hasLocation2 = !!getLocation2;
|
||||
|
||||
return {
|
||||
get hasNext() { return hasNext; },
|
||||
get isNextNewInstance() { return isNextNewInstance; },
|
||||
@@ -60,12 +66,14 @@ export function LocationIterator(groupCount: number, instanceCount: number, stri
|
||||
count: groupCount * instanceCount,
|
||||
stride,
|
||||
nonInstanceable,
|
||||
hasLocation2,
|
||||
move() {
|
||||
if (hasNext) {
|
||||
value.groupIndex = groupIndex;
|
||||
value.instanceIndex = instanceIndex;
|
||||
value.index = instanceIndex * groupCount + groupIndex;
|
||||
value.location = getLocation(groupIndex, voidInstances ? -1 : instanceIndex);
|
||||
if (hasLocation2) value.location2 = getLocation2(groupIndex, voidInstances ? -1 : instanceIndex);
|
||||
value.isSecondary = isSecondary(groupIndex, voidInstances ? -1 : instanceIndex);
|
||||
groupIndex += stride;
|
||||
if (groupIndex === groupCount) {
|
||||
@@ -81,6 +89,7 @@ export function LocationIterator(groupCount: number, instanceCount: number, stri
|
||||
},
|
||||
reset() {
|
||||
value.location = NullLocation;
|
||||
value.location2 = NullLocation;
|
||||
value.index = 0;
|
||||
value.groupIndex = 0;
|
||||
value.instanceIndex = 0;
|
||||
|
||||
@@ -20,6 +20,7 @@ export const CylindersSchema = {
|
||||
aMapping: AttributeSpec('float32', 3, 0),
|
||||
aScale: AttributeSpec('float32', 1, 0),
|
||||
aCap: AttributeSpec('float32', 1, 0),
|
||||
aColorMode: AttributeSpec('float32', 1, 0),
|
||||
elements: ElementsSpec('uint32'),
|
||||
|
||||
padding: ValueSpec('number'),
|
||||
@@ -30,6 +31,7 @@ export const CylindersSchema = {
|
||||
dSolidInterior: DefineSpec('boolean'),
|
||||
uBumpFrequency: UniformSpec('f', 'material'),
|
||||
uBumpAmplitude: UniformSpec('f', 'material'),
|
||||
dDualColor: DefineSpec('boolean'),
|
||||
};
|
||||
export type CylindersSchema = typeof CylindersSchema
|
||||
export type CylindersValues = Values<CylindersSchema>
|
||||
|
||||
@@ -5,9 +5,29 @@ export const assign_color_varying = `
|
||||
#elif defined(dColorType_instance)
|
||||
vColor.rgb = readFromTexture(tColor, aInstance, uColorTexDim).rgb;
|
||||
#elif defined(dColorType_group)
|
||||
vColor.rgb = readFromTexture(tColor, group, uColorTexDim).rgb;
|
||||
#if defined(dDualColor)
|
||||
vec4 color2;
|
||||
if (aColorMode == 2.0) {
|
||||
vColor.rgb = readFromTexture(tColor, group, uColorTexDim).rgb;
|
||||
} else {
|
||||
vColor.rgb = readFromTexture(tColor, group * 2.0, uColorTexDim).rgb;
|
||||
color2.rgb = readFromTexture(tColor, group * 2.0 + 1.0, uColorTexDim).rgb;
|
||||
}
|
||||
#else
|
||||
vColor.rgb = readFromTexture(tColor, group, uColorTexDim).rgb;
|
||||
#endif
|
||||
#elif defined(dColorType_groupInstance)
|
||||
vColor.rgb = readFromTexture(tColor, aInstance * float(uGroupCount) + group, uColorTexDim).rgb;
|
||||
#if defined(dDualColor)
|
||||
vec4 color2;
|
||||
if (aColorMode == 2.0) {
|
||||
vColor.rgb = readFromTexture(tColor, aInstance * float(uGroupCount) + group, uColorTexDim).rgb;
|
||||
} else {
|
||||
vColor.rgb = readFromTexture(tColor, (aInstance * float(uGroupCount) + group) * 2.0, uColorTexDim).rgb;
|
||||
color2.rgb = readFromTexture(tColor, (aInstance * float(uGroupCount) + group) * 2.0 + 1.0, uColorTexDim).rgb;
|
||||
}
|
||||
#else
|
||||
vColor.rgb = readFromTexture(tColor, aInstance * float(uGroupCount) + group, uColorTexDim).rgb;
|
||||
#endif
|
||||
#elif defined(dColorType_vertex)
|
||||
vColor.rgb = readFromTexture(tColor, VertexID, uColorTexDim).rgb;
|
||||
#elif defined(dColorType_vertexInstance)
|
||||
@@ -90,4 +110,4 @@ export const assign_color_varying = `
|
||||
#endif
|
||||
vTransparency *= uTransparencyStrength;
|
||||
#endif
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -121,4 +121,4 @@ export const assign_material_color = `
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -49,4 +49,4 @@ uniform float uBumpiness;
|
||||
#ifdef dTransparency
|
||||
varying float vTransparency;
|
||||
#endif
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -90,4 +90,4 @@ uniform float uBumpiness;
|
||||
#endif
|
||||
uniform float uTransparencyStrength;
|
||||
#endif
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -26,6 +26,7 @@ attribute vec3 aStart;
|
||||
attribute vec3 aEnd;
|
||||
attribute float aScale;
|
||||
attribute float aCap;
|
||||
attribute float aColorMode;
|
||||
|
||||
varying mat4 vTransform;
|
||||
varying vec3 vStart;
|
||||
@@ -54,9 +55,11 @@ void main() {
|
||||
vModelPosition = (vStart + vEnd) * 0.5;
|
||||
vec3 camDir = -mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
|
||||
vec3 dir = vEnd - vStart;
|
||||
float f = aMapping.x > 0.0 ? 1.0 : 0.0;
|
||||
// ensure cylinder 'dir' is pointing towards the camera
|
||||
if(dot(camDir, dir) < 0.0) {
|
||||
dir = -dir;
|
||||
f = 1.0 - f;
|
||||
}
|
||||
|
||||
vec3 left = cross(camDir, dir);
|
||||
@@ -76,6 +79,18 @@ void main() {
|
||||
gl_Position.z = (uProjection * mvPosition).z;
|
||||
}
|
||||
|
||||
#if defined(dDualColor) && defined(dRenderVariant_color) && (defined(dColorType_group) || defined(dColorType_groupInstance))
|
||||
// dual-color mixing
|
||||
// - for aColorMode between 0 and 1 use aColorMode to interpolate
|
||||
// - for aColorMode == 2 do nothing, i.e., use vColor
|
||||
// - for aColorMode == 3 use position on cylinder axis to interpolate
|
||||
if (aColorMode <= 1.0){
|
||||
vColor.rgb = mix(vColor.rgb, color2.rgb, aColorMode);
|
||||
} else if (aColorMode == 3.0) {
|
||||
vColor.rgb = mix(vColor.rgb, color2.rgb, mix(-0.25, 1.25, f / 1.5));
|
||||
}
|
||||
#endif
|
||||
|
||||
#include clip_instance
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.382, IHM 1.24, MA 1.4.5.
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.386, IHM 1.25, MA 1.4.6.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.382, IHM 1.24, MA 1.4.5.
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.386, IHM 1.25, MA 1.4.6.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.382, IHM 1.24, MA 1.4.5.
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.386, IHM 1.25, MA 1.4.6.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
@@ -1966,7 +1966,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The identifying content type of the related entry.
|
||||
*/
|
||||
content_type: Aliased<'minimized average structure' | 'representative structure' | 'ensemble' | 'derivative structure' | 'native structure' | 'associated EM volume' | 'other EM volume' | 'associated NMR restraints' | 'associated structure factors' | 'associated SAS data' | 'protein target sequence and/or protocol data' | 'split' | 're-refinement' | 'complete structure' | 'unspecified' | 'other'>(str),
|
||||
content_type: Aliased<'minimized average structure' | 'representative structure' | 'ensemble' | 'derivative structure' | 'native structure' | 'associated EM volume' | 'other EM volume' | 'focused EM volume' | 'consensus EM volume' | 'associated NMR restraints' | 'associated structure factors' | 'associated SAS data' | 'protein target sequence and/or protocol data' | 'split' | 're-refinement' | 'complete structure' | 'unspecified' | 'other'>(str),
|
||||
},
|
||||
/**
|
||||
* The PDBX_ENTITY_NONPOLY category provides a mapping between
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2024 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>
|
||||
@@ -43,6 +43,7 @@ import { PlaneParams, PlaneRepresentation } from '../../mol-repr/shape/loci/plan
|
||||
import { Substance } from '../../mol-theme/substance';
|
||||
import { Material } from '../../mol-util/material';
|
||||
import { lerp } from '../../mol-math/interpolate';
|
||||
import { MarkerAction, MarkerActions } from '../../mol-util/marker-action';
|
||||
|
||||
export { StructureRepresentation3D };
|
||||
export { ExplodeStructureRepresentation3D };
|
||||
@@ -1143,6 +1144,11 @@ const StructureSelectionsLabel3D = PluginStateTransform.BuiltIn({
|
||||
const data = getLabelDataFromStructureSelections(a.data);
|
||||
const repr = LabelRepresentation({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.structure.themes }, () => LabelParams);
|
||||
await repr.createOrUpdate(params, data).runInContext(ctx);
|
||||
|
||||
// Support interactivity when needed
|
||||
const pickable = !!(params.snapshotKey?.trim() || params.tooltip?.trim());
|
||||
repr.setState({ pickable, markerActions: pickable ? MarkerActions.Highlighting : MarkerAction.None });
|
||||
|
||||
return new SO.Shape.Representation3D({ repr, sourceData: data }, { label: `Label` });
|
||||
});
|
||||
},
|
||||
@@ -1152,6 +1158,11 @@ const StructureSelectionsLabel3D = PluginStateTransform.BuiltIn({
|
||||
const data = getLabelDataFromStructureSelections(a.data);
|
||||
await b.data.repr.createOrUpdate(props, data).runInContext(ctx);
|
||||
b.data.sourceData = data;
|
||||
|
||||
// Update interactivity
|
||||
const pickable = !!(newParams.snapshotKey?.trim() || newParams.tooltip?.trim());
|
||||
b.data.repr.setState({ pickable, markerActions: pickable ? MarkerActions.Highlighting : MarkerAction.None });
|
||||
|
||||
return StateTransformer.UpdateResult.Updated;
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2024 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>
|
||||
@@ -286,7 +286,7 @@ export class SelectionViewportControls extends PluginUIComponent {
|
||||
}
|
||||
|
||||
export class LociLabels extends PluginUIComponent<{}, { labels: ReadonlyArray<LociLabel> }> {
|
||||
state = { labels: [] };
|
||||
state = { labels: [] as string[] };
|
||||
|
||||
componentDidMount() {
|
||||
this.subscribe(this.plugin.behaviors.labels.highlight, e => this.setState({ labels: e.labels }));
|
||||
@@ -298,7 +298,15 @@ export class LociLabels extends PluginUIComponent<{}, { labels: ReadonlyArray<Lo
|
||||
}
|
||||
|
||||
return <div className='msp-highlight-info'>
|
||||
{this.state.labels.map((e, i) => <div key={'' + i} dangerouslySetInnerHTML={{ __html: e }} />)}
|
||||
{this.state.labels.map((e, i) => {
|
||||
if (e.indexOf('\n') > 0) {
|
||||
return <div className='msp-highlight-markdown-row' key={'' + i}>
|
||||
<Markdown skipHtml>{e}</Markdown>
|
||||
</div>;
|
||||
}
|
||||
|
||||
return <div className='msp-highlight-simple-row' key={'' + i} dangerouslySetInnerHTML={{ __html: e }} />;
|
||||
})}
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2024 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>
|
||||
@@ -244,6 +244,7 @@ function renderSimple(options: { props: ParamProps<any>, state: { showHelp: bool
|
||||
const _className = [];
|
||||
if (props.param.shortLabel) _className.push('msp-control-label-short');
|
||||
if (props.param.twoColumns) _className.push('msp-control-col-2');
|
||||
if (props.param.multiline) _className.push('msp-control-twoline');
|
||||
const className = _className.join(' ');
|
||||
|
||||
const label = props.param.label || camelCaseToWords(props.name);
|
||||
@@ -403,32 +404,71 @@ export class NumberRangeControl extends SimpleParam<PD.Numeric> {
|
||||
}
|
||||
|
||||
export class TextControl extends SimpleParam<PD.Text> {
|
||||
onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
updateValue = (value: string) => {
|
||||
if (value !== this.props.value) {
|
||||
this.update(value);
|
||||
}
|
||||
};
|
||||
|
||||
onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if ((e.keyCode === 13 || e.charCode === 13 || e.key === 'Enter')) {
|
||||
if (this.props.onEnter) this.props.onEnter();
|
||||
}
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
renderControl() {
|
||||
const placeholder = this.props.param.label || camelCaseToWords(this.props.name);
|
||||
return <input type='text'
|
||||
value={this.props.value || ''}
|
||||
placeholder={placeholder}
|
||||
onChange={this.onChange}
|
||||
onKeyPress={this.props.onEnter ? this.onKeyPress : void 0}
|
||||
disabled={this.props.isDisabled}
|
||||
/>;
|
||||
const placeholder = this.props.param.placeholder || this.props.param.label || camelCaseToWords(this.props.name);
|
||||
return <TextCtrl props={this.props} placeholder={placeholder} update={this.updateValue} />;
|
||||
}
|
||||
}
|
||||
|
||||
function TextCtrl({ props, placeholder, update }: { props: ParamProps<PD.Text>, placeholder: string, update: (v: string) => any }) {
|
||||
const [value, setValue] = React.useState(props.value);
|
||||
React.useEffect(() => setValue(props.value), [props.value]);
|
||||
|
||||
if (props.param.multiline) {
|
||||
return <div className='msp-control-text-area-wrapper'>
|
||||
<textarea
|
||||
value={props.param.disableInteractiveUpdates ? (value || '') : props.value}
|
||||
placeholder={placeholder}
|
||||
onChange={e => {
|
||||
if (props.param.disableInteractiveUpdates) setValue(e.target.value);
|
||||
else update(e.target.value);
|
||||
}}
|
||||
onBlur={e => {
|
||||
if (props.param.disableInteractiveUpdates) update(e.target.value);
|
||||
}}
|
||||
onKeyDown={e => {
|
||||
if (e.key === 'Enter' && (e.shiftKey || e.ctrlKey || e.metaKey)) {
|
||||
e.currentTarget.blur();
|
||||
}
|
||||
}}
|
||||
disabled={props.isDisabled}
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
return <input
|
||||
type='text'
|
||||
value={props.param.disableInteractiveUpdates ? (value || '') : props.value}
|
||||
placeholder={placeholder}
|
||||
onChange={e => {
|
||||
if (props.param.disableInteractiveUpdates) setValue(e.target.value);
|
||||
else update(e.target.value);
|
||||
}}
|
||||
onBlur={e => {
|
||||
if (props.param.disableInteractiveUpdates) update(e.target.value);
|
||||
}}
|
||||
disabled={props.isDisabled}
|
||||
onKeyDown={e => {
|
||||
if (e.key !== 'Enter') return;
|
||||
|
||||
if (props.onEnter) {
|
||||
e.stopPropagation();
|
||||
props.onEnter();
|
||||
} else if (e.key === 'Enter' && (e.shiftKey || e.ctrlKey || e.metaKey)) {
|
||||
e.currentTarget.blur();
|
||||
} else if (props.param.disableInteractiveUpdates) {
|
||||
update(value);
|
||||
}
|
||||
}}
|
||||
/>;
|
||||
}
|
||||
|
||||
export class PureSelectControl extends React.PureComponent<ParamProps<PD.Select<string | number>> & { title?: string }> {
|
||||
protected update(value: string | number) {
|
||||
this.props.onChange({ param: this.props.param, name: this.props.name, value });
|
||||
|
||||
@@ -71,6 +71,10 @@
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.msp-control-twoline {
|
||||
height: 2 * $row-height !important;
|
||||
}
|
||||
|
||||
.msp-control-group {
|
||||
position: relative;
|
||||
}
|
||||
@@ -418,9 +422,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.msp-text-area-wrapper {
|
||||
.msp-control-text-area-wrapper, .msp-text-area-wrapper {
|
||||
position: relative;
|
||||
height: 3 * $row-height !important;
|
||||
textarea {
|
||||
border: none;
|
||||
width: 100%;
|
||||
@@ -431,4 +434,12 @@
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.msp-control-text-area-wrapper {
|
||||
height: 2 * $row-height !important;
|
||||
}
|
||||
|
||||
.msp-text-area-wrapper {
|
||||
height: 3 * $row-height !important;
|
||||
}
|
||||
|
||||
@@ -142,13 +142,19 @@
|
||||
padding: $info-vertical-padding $control-spacing;
|
||||
background: $default-background; //$highlight-info-background;
|
||||
opacity: 90%;
|
||||
|
||||
// min-height: $row-height;
|
||||
text-align: right;
|
||||
max-width: 400px;
|
||||
|
||||
@include non-selectable;
|
||||
}
|
||||
|
||||
.msp-highlight-markdown-row {
|
||||
padding-left: $control-spacing;
|
||||
}
|
||||
|
||||
.msp-highlight-simple-row {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.msp-highlight-info-hr {
|
||||
margin-inline: 0px;
|
||||
margin-block: 3px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2024 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>
|
||||
@@ -264,12 +264,20 @@ export const FocusLoci = PluginBehavior.create<FocusLociProps>({
|
||||
this.subscribeObservable(this.ctx.behaviors.interaction.click, ({ current, button, modifiers }) => {
|
||||
const { clickFocus, clickFocusAdd, clickFocusSelectMode, clickFocusAddSelectMode } = this.params.bindings;
|
||||
|
||||
const binding = this.ctx.selectionMode ? clickFocusSelectMode : clickFocus;
|
||||
const matched = Binding.match(binding, button, modifiers);
|
||||
|
||||
// Support snapshot key property, in which case ignore the focus functionality
|
||||
const snapshotKey = current.repr?.props?.snapshotKey?.trim() ?? '';
|
||||
if (!this.ctx.selectionMode && matched && snapshotKey) {
|
||||
this.ctx.managers.snapshot.applyKey(snapshotKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// only apply structure focus for appropriate granularity
|
||||
const { granularity } = this.ctx.managers.interactivity.props;
|
||||
if (granularity !== 'residue' && granularity !== 'element') return;
|
||||
|
||||
const binding = this.ctx.selectionMode ? clickFocusSelectMode : clickFocus;
|
||||
const matched = Binding.match(binding, button, modifiers);
|
||||
const bindingAdd = this.ctx.selectionMode ? clickFocusAddSelectMode : clickFocusAdd;
|
||||
const matchedAdd = Binding.match(bindingAdd, button, modifiers);
|
||||
if (!matched && !matchedAdd) return;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-24 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Loci } from '../../../mol-model/loci';
|
||||
@@ -26,13 +27,15 @@ const TextParams = {
|
||||
type TextParams = typeof TextParams
|
||||
|
||||
const LabelVisuals = {
|
||||
'text': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<LabelData, TextParams>) => ShapeRepresentation(getTextShape, Text.Utils, { modifyState: s => ({ ...s, pickable: false }) }),
|
||||
'text': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<LabelData, TextParams>) => ShapeRepresentation(getTextShape, Text.Utils),
|
||||
};
|
||||
|
||||
export const LabelParams = {
|
||||
...TextParams,
|
||||
scaleByRadius: PD.Boolean(true),
|
||||
visuals: PD.MultiSelect(['text'], PD.objectToOptions(LabelVisuals)),
|
||||
snapshotKey: PD.Text('', { isEssential: true, disableInteractiveUpdates: true, description: 'Activate the snapshot with the provided key when clicking on the label' }),
|
||||
tooltip: PD.Text('', { isEssential: true, multiline: true, disableInteractiveUpdates: true, placeholder: 'Tooltip', description: 'Tooltip text to be displayed when hovering over the label' }),
|
||||
};
|
||||
|
||||
export type LabelParams = typeof LabelParams
|
||||
@@ -69,13 +72,18 @@ function buildText(data: LabelData, props: LabelProps, text?: Text): Text {
|
||||
function getTextShape(ctx: RuntimeContext, data: LabelData, props: LabelProps, shape?: Shape<Text>) {
|
||||
const text = buildText(data, props, shape && shape.geometry);
|
||||
const name = getLabelName(data);
|
||||
const tooltip = props.tooltip?.trim() ?? '';
|
||||
const customLabel = props.customText.trim();
|
||||
const getLabel = customLabel
|
||||
? function (groupId: number) {
|
||||
return customLabel;
|
||||
} : function (groupId: number) {
|
||||
return label(data.infos[groupId]);
|
||||
};
|
||||
let getLabel: (groupId: number) => any;
|
||||
|
||||
if (tooltip) {
|
||||
getLabel = (_: number) => tooltip;
|
||||
} else if (customLabel) {
|
||||
getLabel = (_: number) => customLabel;
|
||||
} else {
|
||||
getLabel = (groupId: number) => label(data.infos[groupId]);
|
||||
}
|
||||
|
||||
return Shape.create(name, data, text, () => props.textColor, () => props.textSize, getLabel);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
@@ -52,7 +53,7 @@ function createComplexRenderObject<G extends Geometry>(structure: Structure, geo
|
||||
interface ComplexVisualBuilder<P extends StructureParams, G extends Geometry> {
|
||||
defaultProps: PD.Values<P>
|
||||
createGeometry(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<P>, geometry?: G): Promise<G> | G
|
||||
createLocationIterator(structure: Structure): LocationIterator
|
||||
createLocationIterator(structure: Structure, props: PD.Values<P>): LocationIterator
|
||||
getLoci(pickingId: PickingId, structure: Structure, id: number): Loci
|
||||
eachLocation(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean, isMarking: boolean): boolean,
|
||||
setUpdateState(state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure): void
|
||||
@@ -143,7 +144,7 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
|
||||
|
||||
function update(newGeometry?: G) {
|
||||
if (updateState.createNew) {
|
||||
locationIt = createLocationIterator(newStructure);
|
||||
locationIt = createLocationIterator(newStructure, newProps);
|
||||
if (newGeometry) {
|
||||
renderObject = createComplexRenderObject(newStructure, newGeometry, locationIt, newTheme, newProps, materialId);
|
||||
positionIt = createPositionIterator(newGeometry, renderObject.values);
|
||||
@@ -157,7 +158,7 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
|
||||
|
||||
if (updateState.updateTransform) {
|
||||
// console.log('update transform')
|
||||
locationIt = createLocationIterator(newStructure);
|
||||
locationIt = createLocationIterator(newStructure, newProps);
|
||||
const { instanceCount, groupCount } = locationIt;
|
||||
if (newProps.instanceGranularity) {
|
||||
createMarkers(instanceCount, 'instance', renderObject.values);
|
||||
|
||||
@@ -28,6 +28,7 @@ export const BackboneParams = {
|
||||
sizeAspectRatio: PD.Numeric(1, { min: 0.1, max: 3, step: 0.1 }),
|
||||
visuals: PD.MultiSelect(['polymer-backbone-cylinder', 'polymer-backbone-sphere', 'polymer-gap'], PD.objectToOptions(BackboneVisuals)),
|
||||
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
colorMode: PD.Select('default', PD.arrayToOptions(['default', 'interpolate'] as const), { ...BaseGeometry.ShadingCategory, isHidden: true }),
|
||||
};
|
||||
export type BackboneParams = typeof BackboneParams
|
||||
export function getBackboneParams(ctx: ThemeRegistryContext, structure: Structure) {
|
||||
|
||||
@@ -47,6 +47,7 @@ export const CartoonParams = {
|
||||
sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
|
||||
visuals: PD.MultiSelect(['polymer-trace', 'polymer-gap', 'nucleotide-ring', 'nucleotide-atomic-ring-fill', 'nucleotide-atomic-bond', 'nucleotide-atomic-element'], PD.objectToOptions(CartoonVisuals)),
|
||||
bumpFrequency: PD.Numeric(2, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
|
||||
colorMode: PD.Select('default', PD.arrayToOptions(['default', 'interpolate'] as const), { ...BaseGeometry.ShadingCategory, isHidden: true }),
|
||||
};
|
||||
|
||||
export type CartoonParams = typeof CartoonParams
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
@@ -55,7 +56,7 @@ function createUnitsRenderObject<G extends Geometry>(structureGroup: StructureGr
|
||||
interface UnitsVisualBuilder<P extends StructureParams, G extends Geometry> {
|
||||
defaultProps: PD.Values<P>
|
||||
createGeometry(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<P>, geometry?: G): Promise<G> | G
|
||||
createLocationIterator(structureGroup: StructureGroup): LocationIterator
|
||||
createLocationIterator(structureGroup: StructureGroup, props: PD.Values<P>): LocationIterator
|
||||
getLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number): Loci
|
||||
eachLocation(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean, isMarking: boolean): boolean
|
||||
setUpdateState(state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup): void
|
||||
@@ -182,7 +183,7 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
|
||||
|
||||
function update(newGeometry?: G) {
|
||||
if (updateState.createNew) {
|
||||
locationIt = createLocationIterator(newStructureGroup);
|
||||
locationIt = createLocationIterator(newStructureGroup, newProps);
|
||||
if (newGeometry) {
|
||||
renderObject = createUnitsRenderObject(newStructureGroup, newGeometry, locationIt, newTheme, newProps, materialId);
|
||||
positionIt = createPositionIterator(newGeometry, renderObject.values);
|
||||
@@ -196,7 +197,7 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
|
||||
|
||||
if (updateState.updateTransform) {
|
||||
// console.log('update transform');
|
||||
locationIt = createLocationIterator(newStructureGroup);
|
||||
locationIt = createLocationIterator(newStructureGroup, newProps);
|
||||
const { instanceCount, groupCount } = locationIt;
|
||||
if (newProps.instanceGranularity) {
|
||||
createMarkers(instanceCount, 'instance', renderObject.values);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
@@ -213,7 +214,7 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex
|
||||
return ComplexCylindersVisual<InterUnitBondCylinderParams>({
|
||||
defaultProps: PD.getDefaultValues(InterUnitBondCylinderParams),
|
||||
createGeometry: createInterUnitBondCylinderImpostors,
|
||||
createLocationIterator: BondIterator.fromStructure,
|
||||
createLocationIterator: (structure: Structure, props: PD.Values<InterUnitBondCylinderParams>) => BondIterator.fromStructure(structure, { includeLocation2: props.colorMode === 'interpolate' }),
|
||||
getLoci: getInterBondLoci,
|
||||
eachLocation: eachInterBond,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<InterUnitBondCylinderParams>, currentProps: PD.Values<InterUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure) => {
|
||||
@@ -238,6 +239,12 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex
|
||||
newProps.multipleBonds !== currentProps.multipleBonds
|
||||
);
|
||||
|
||||
if (newProps.colorMode !== currentProps.colorMode) {
|
||||
state.createGeometry = true;
|
||||
state.updateTransform = true;
|
||||
state.updateColor = true;
|
||||
}
|
||||
|
||||
if (newStructure.interUnitBonds !== currentStructure.interUnitBonds) {
|
||||
state.createGeometry = true;
|
||||
state.updateTransform = true;
|
||||
@@ -255,7 +262,7 @@ export function InterUnitBondCylinderMeshVisual(materialId: number): ComplexVisu
|
||||
return ComplexMeshVisual<InterUnitBondCylinderParams>({
|
||||
defaultProps: PD.getDefaultValues(InterUnitBondCylinderParams),
|
||||
createGeometry: createInterUnitBondCylinderMesh,
|
||||
createLocationIterator: BondIterator.fromStructure,
|
||||
createLocationIterator: (structure: Structure) => BondIterator.fromStructure(structure),
|
||||
getLoci: getInterBondLoci,
|
||||
eachLocation: eachInterBond,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<InterUnitBondCylinderParams>, currentProps: PD.Values<InterUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure) => {
|
||||
|
||||
@@ -127,7 +127,7 @@ export function InterUnitBondLineVisual(materialId: number): ComplexVisual<Inter
|
||||
return ComplexLinesVisual<InterUnitBondLineParams>({
|
||||
defaultProps: PD.getDefaultValues(InterUnitBondLineParams),
|
||||
createGeometry: createInterUnitBondLines,
|
||||
createLocationIterator: BondIterator.fromStructure,
|
||||
createLocationIterator: (structure: Structure) => BondIterator.fromStructure(structure),
|
||||
getLoci: getInterBondLoci,
|
||||
eachLocation: eachInterBond,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<InterUnitBondLineParams>, currentProps: PD.Values<InterUnitBondLineParams>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure) => {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
@@ -230,7 +231,7 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi
|
||||
return UnitsCylindersVisual<IntraUnitBondCylinderParams>({
|
||||
defaultProps: PD.getDefaultValues(IntraUnitBondCylinderParams),
|
||||
createGeometry: createIntraUnitBondCylinderImpostors,
|
||||
createLocationIterator: BondIterator.fromGroup,
|
||||
createLocationIterator: (structureGroup: StructureGroup, props) => BondIterator.fromGroup(structureGroup, { includeLocation2: props.colorMode === 'interpolate' }),
|
||||
getLoci: getIntraBondLoci,
|
||||
eachLocation: eachIntraBond,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<IntraUnitBondCylinderParams>, currentProps: PD.Values<IntraUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup) => {
|
||||
@@ -256,6 +257,12 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi
|
||||
newProps.multipleBonds !== currentProps.multipleBonds
|
||||
);
|
||||
|
||||
if (newProps.colorMode !== currentProps.colorMode) {
|
||||
state.createGeometry = true;
|
||||
state.updateTransform = true;
|
||||
state.updateColor = true;
|
||||
}
|
||||
|
||||
const newUnit = newStructureGroup.group.units[0];
|
||||
const currentUnit = currentStructureGroup.group.units[0];
|
||||
if (Unit.isAtomic(newUnit) && Unit.isAtomic(currentUnit)) {
|
||||
@@ -277,7 +284,7 @@ export function IntraUnitBondCylinderMeshVisual(materialId: number): UnitsVisual
|
||||
return UnitsMeshVisual<IntraUnitBondCylinderParams>({
|
||||
defaultProps: PD.getDefaultValues(IntraUnitBondCylinderParams),
|
||||
createGeometry: createIntraUnitBondCylinderMesh,
|
||||
createLocationIterator: BondIterator.fromGroup,
|
||||
createLocationIterator: (structureGroup: StructureGroup) => BondIterator.fromGroup(structureGroup),
|
||||
getLoci: getIntraBondLoci,
|
||||
eachLocation: eachIntraBond,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<IntraUnitBondCylinderParams>, currentProps: PD.Values<IntraUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup) => {
|
||||
|
||||
@@ -153,7 +153,7 @@ export function IntraUnitBondLineVisual(materialId: number): UnitsVisual<IntraUn
|
||||
return UnitsLinesVisual<IntraUnitBondLineParams>({
|
||||
defaultProps: PD.getDefaultValues(IntraUnitBondLineParams),
|
||||
createGeometry: createIntraUnitBondLines,
|
||||
createLocationIterator: BondIterator.fromGroup,
|
||||
createLocationIterator: (structureGroup: StructureGroup) => BondIterator.fromGroup(structureGroup),
|
||||
getLoci: getIntraBondLoci,
|
||||
eachLocation: eachIntraBond,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<IntraUnitBondLineParams>, currentProps: PD.Values<IntraUnitBondLineParams>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup) => {
|
||||
|
||||
@@ -83,6 +83,7 @@ function createNucleotideAtomicBondImpostor(ctx: VisualContext, unit: Unit, stru
|
||||
const residueIt = Segmentation.transientSegments(residueAtomSegments, elements);
|
||||
|
||||
let i = 0;
|
||||
const colorModeFlag = 2.0;
|
||||
while (chainIt.hasNext) {
|
||||
residueIt.setSegment(chainIt.move());
|
||||
|
||||
@@ -99,14 +100,14 @@ function createNucleotideAtomicBondImpostor(ctx: VisualContext, unit: Unit, stru
|
||||
|
||||
// trace cylinder
|
||||
pos(idx.trace, pTrace);
|
||||
builder.add(pC3_1[0], pC3_1[1], pC3_1[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, i);
|
||||
builder.add(pC3_1[0], pC3_1[1], pC3_1[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, colorModeFlag, i);
|
||||
|
||||
// sugar ring
|
||||
builder.add(pC3_1[0], pC3_1[1], pC3_1[2], pC4_1[0], pC4_1[1], pC4_1[2], 1, true, true, i);
|
||||
builder.add(pC4_1[0], pC4_1[1], pC4_1[2], pO4_1[0], pO4_1[1], pO4_1[2], 1, true, true, i);
|
||||
builder.add(pO4_1[0], pO4_1[1], pO4_1[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, i);
|
||||
builder.add(pC1_1[0], pC1_1[1], pC1_1[2], pC2_1[0], pC2_1[1], pC2_1[2], 1, true, true, i);
|
||||
builder.add(pC2_1[0], pC2_1[1], pC2_1[2], pC3_1[0], pC3_1[1], pC3_1[2], 1, true, true, i);
|
||||
builder.add(pC3_1[0], pC3_1[1], pC3_1[2], pC4_1[0], pC4_1[1], pC4_1[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC4_1[0], pC4_1[1], pC4_1[2], pO4_1[0], pO4_1[1], pO4_1[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pO4_1[0], pO4_1[1], pO4_1[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC1_1[0], pC1_1[1], pC1_1[2], pC2_1[0], pC2_1[1], pC2_1[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC2_1[0], pC2_1[1], pC2_1[2], pC3_1[0], pC3_1[1], pC3_1[2], 1, true, true, colorModeFlag, i);
|
||||
}
|
||||
|
||||
const { isPurine, isPyrimidine } = getNucleotideBaseType(unit, residueIndex);
|
||||
@@ -116,26 +117,26 @@ function createNucleotideAtomicBondImpostor(ctx: VisualContext, unit: Unit, stru
|
||||
|
||||
if (idx.C1_1 !== -1 && idx.N9 !== -1) {
|
||||
pos(idx.C1_1, pC1_1); pos(idx.N9, pN9);
|
||||
builder.add(pN9[0], pN9[1], pN9[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, i);
|
||||
builder.add(pN9[0], pN9[1], pN9[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, colorModeFlag, i);
|
||||
} else if (idx.N9 !== -1 && idx.trace !== -1) {
|
||||
pos(idx.N9, pN9); pos(idx.trace, pTrace);
|
||||
builder.add(pN9[0], pN9[1], pN9[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, i);
|
||||
builder.add(pN9[0], pN9[1], pN9[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, colorModeFlag, i);
|
||||
}
|
||||
|
||||
if (hasPurinIndices(idx)) {
|
||||
pos(idx.N1, pN1); pos(idx.C2, pC2); pos(idx.N3, pN3); pos(idx.C4, pC4); pos(idx.C5, pC5); pos(idx.C6, pC6); pos(idx.N7, pN7); pos(idx.C8, pC8); pos(idx.N9, pN9);
|
||||
|
||||
// base ring
|
||||
builder.add(pN9[0], pN9[1], pN9[2], pC8[0], pC8[1], pC8[2], 1, true, true, i);
|
||||
builder.add(pC8[0], pC8[1], pC8[2], pN7[0], pN7[1], pN7[2], 1, true, true, i);
|
||||
builder.add(pN7[0], pN7[1], pN7[2], pC5[0], pC5[1], pC5[2], 1, true, true, i);
|
||||
builder.add(pC5[0], pC5[1], pC5[2], pC6[0], pC6[1], pC6[2], 1, true, true, i);
|
||||
builder.add(pC6[0], pC6[1], pC6[2], pN1[0], pN1[1], pN1[2], 1, true, true, i);
|
||||
builder.add(pN1[0], pN1[1], pN1[2], pC2[0], pC2[1], pC2[2], 1, true, true, i);
|
||||
builder.add(pC2[0], pC2[1], pC2[2], pN3[0], pN3[1], pN3[2], 1, true, true, i);
|
||||
builder.add(pN3[0], pN3[1], pN3[2], pC4[0], pC4[1], pC4[2], 1, true, true, i);
|
||||
builder.add(pC4[0], pC4[1], pC4[2], pC5[0], pC5[1], pC5[2], 1, true, true, i);
|
||||
builder.add(pC4[0], pC4[1], pC4[2], pN9[0], pN9[1], pN9[2], 1, true, true, i);
|
||||
builder.add(pN9[0], pN9[1], pN9[2], pC8[0], pC8[1], pC8[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC8[0], pC8[1], pC8[2], pN7[0], pN7[1], pN7[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pN7[0], pN7[1], pN7[2], pC5[0], pC5[1], pC5[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC5[0], pC5[1], pC5[2], pC6[0], pC6[1], pC6[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC6[0], pC6[1], pC6[2], pN1[0], pN1[1], pN1[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pN1[0], pN1[1], pN1[2], pC2[0], pC2[1], pC2[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC2[0], pC2[1], pC2[2], pN3[0], pN3[1], pN3[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pN3[0], pN3[1], pN3[2], pC4[0], pC4[1], pC4[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC4[0], pC4[1], pC4[2], pC5[0], pC5[1], pC5[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC4[0], pC4[1], pC4[2], pN9[0], pN9[1], pN9[2], 1, true, true, colorModeFlag, i);
|
||||
|
||||
}
|
||||
} else if (isPyrimidine) {
|
||||
@@ -143,22 +144,22 @@ function createNucleotideAtomicBondImpostor(ctx: VisualContext, unit: Unit, stru
|
||||
|
||||
if (idx.C1_1 !== -1 && idx.N1 !== -1) {
|
||||
pos(idx.N1, pN1); pos(idx.C1_1, pC1_1);
|
||||
builder.add(pN1[0], pN1[1], pN1[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, i);
|
||||
builder.add(pN1[0], pN1[1], pN1[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, colorModeFlag, i);
|
||||
} else if (idx.N1 !== -1 && idx.trace !== -1) {
|
||||
pos(idx.N1, pN1); pos(idx.trace, pTrace);
|
||||
builder.add(pN1[0], pN1[1], pN1[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, i);
|
||||
builder.add(pN1[0], pN1[1], pN1[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, colorModeFlag, i);
|
||||
}
|
||||
|
||||
if (hasPyrimidineIndices(idx)) {
|
||||
pos(idx.N1, pN1); pos(idx.C2, pC2); pos(idx.N3, pN3); pos(idx.C4, pC4); pos(idx.C5, pC5); pos(idx.C6, pC6);
|
||||
|
||||
// base ring
|
||||
builder.add(pN1[0], pN1[1], pN1[2], pC6[0], pC6[1], pC6[2], 1, true, true, i);
|
||||
builder.add(pC6[0], pC6[1], pC6[2], pC5[0], pC5[1], pC5[2], 1, true, true, i);
|
||||
builder.add(pC5[0], pC5[1], pC5[2], pC4[0], pC4[1], pC4[2], 1, true, true, i);
|
||||
builder.add(pC4[0], pC4[1], pC4[2], pN3[0], pN3[1], pN3[2], 1, true, true, i);
|
||||
builder.add(pN3[0], pN3[1], pN3[2], pC2[0], pC2[1], pC2[2], 1, true, true, i);
|
||||
builder.add(pC2[0], pC2[1], pC2[2], pN1[0], pN1[1], pN1[2], 1, true, true, i);
|
||||
builder.add(pN1[0], pN1[1], pN1[2], pC6[0], pC6[1], pC6[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC6[0], pC6[1], pC6[2], pC5[0], pC5[1], pC5[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC5[0], pC5[1], pC5[2], pC4[0], pC4[1], pC4[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC4[0], pC4[1], pC4[2], pN3[0], pN3[1], pN3[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pN3[0], pN3[1], pN3[2], pC2[0], pC2[1], pC2[2], 1, true, true, colorModeFlag, i);
|
||||
builder.add(pC2[0], pC2[1], pC2[2], pN1[0], pN1[1], pN1[2], 1, true, true, colorModeFlag, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,8 +70,8 @@ function createPolymerBackboneCylinderImpostor(ctx: VisualContext, unit: Unit, s
|
||||
const shift = isNucleicType ? NucleicShift : StandardShift;
|
||||
|
||||
v3add(pM, pA, v3scale(pM, v3sub(pM, pB, pA), shift));
|
||||
builder.add(pA[0], pA[1], pA[2], pM[0], pM[1], pM[2], 1, false, false, groupA);
|
||||
builder.add(pM[0], pM[1], pM[2], pB[0], pB[1], pB[2], 1, false, false, groupB);
|
||||
builder.add(pA[0], pA[1], pA[2], pM[0], pM[1], pM[2], 1, false, false, 2, groupA);
|
||||
builder.add(pM[0], pM[1], pM[2], pB[0], pB[1], pB[2], 1, false, false, 2, groupB);
|
||||
};
|
||||
|
||||
eachPolymerBackboneLink(unit, add);
|
||||
@@ -88,7 +88,7 @@ export function PolymerBackboneCylinderImpostorVisual(materialId: number): Units
|
||||
return UnitsCylindersVisual<PolymerBackboneCylinderParams>({
|
||||
defaultProps: PD.getDefaultValues(PolymerBackboneCylinderParams),
|
||||
createGeometry: createPolymerBackboneCylinderImpostor,
|
||||
createLocationIterator: PolymerLocationIterator.fromGroup,
|
||||
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
|
||||
getLoci: getPolymerElementLoci,
|
||||
eachLocation: eachPolymerElement,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerBackboneCylinderParams>, currentProps: PD.Values<PolymerBackboneCylinderParams>) => { },
|
||||
@@ -148,7 +148,7 @@ export function PolymerBackboneCylinderMeshVisual(materialId: number): UnitsVisu
|
||||
return UnitsMeshVisual<PolymerBackboneCylinderParams>({
|
||||
defaultProps: PD.getDefaultValues(PolymerBackboneCylinderParams),
|
||||
createGeometry: createPolymerBackboneCylinderMesh,
|
||||
createLocationIterator: PolymerLocationIterator.fromGroup,
|
||||
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
|
||||
getLoci: getPolymerElementLoci,
|
||||
eachLocation: eachPolymerElement,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerBackboneCylinderParams>, currentProps: PD.Values<PolymerBackboneCylinderParams>) => {
|
||||
@@ -161,4 +161,4 @@ export function PolymerBackboneCylinderMeshVisual(materialId: number): UnitsVisu
|
||||
return props.tryUseImpostor && !!webgl;
|
||||
}
|
||||
}, materialId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export function PolymerBackboneSphereImpostorVisual(materialId: number): UnitsVi
|
||||
return UnitsSpheresVisual<PolymerBackboneSphereParams>({
|
||||
defaultProps: PD.getDefaultValues(PolymerBackboneSphereParams),
|
||||
createGeometry: createPolymerBackboneSphereImpostor,
|
||||
createLocationIterator: PolymerLocationIterator.fromGroup,
|
||||
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
|
||||
getLoci: getPolymerElementLoci,
|
||||
eachLocation: eachPolymerElement,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerBackboneSphereParams>, currentProps: PD.Values<PolymerBackboneSphereParams>) => { },
|
||||
@@ -116,7 +116,7 @@ export function PolymerBackboneSphereMeshVisual(materialId: number): UnitsVisual
|
||||
return UnitsMeshVisual<PolymerBackboneSphereParams>({
|
||||
defaultProps: PD.getDefaultValues(PolymerBackboneSphereParams),
|
||||
createGeometry: createPolymerBackboneSphereMesh,
|
||||
createLocationIterator: PolymerLocationIterator.fromGroup,
|
||||
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
|
||||
getLoci: getPolymerElementLoci,
|
||||
eachLocation: eachPolymerElement,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerBackboneSphereParams>, currentProps: PD.Values<PolymerBackboneSphereParams>) => {
|
||||
|
||||
@@ -17,6 +17,7 @@ import { isNucleic, SecondaryStructureType } from '../../../mol-model/structure/
|
||||
import { UnitsMeshParams, UnitsVisual, UnitsMeshVisual } from '../units-visual';
|
||||
import { VisualUpdateState } from '../../util';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { StructureGroup } from './util/common';
|
||||
|
||||
const t = Mat4.identity();
|
||||
const sVec = Vec3.zero();
|
||||
@@ -101,7 +102,7 @@ export function PolymerDirectionVisual(materialId: number): UnitsVisual<PolymerD
|
||||
return UnitsMeshVisual<PolymerDirectionParams>({
|
||||
defaultProps: PD.getDefaultValues(PolymerDirectionParams),
|
||||
createGeometry: createPolymerDirectionWedgeMesh,
|
||||
createLocationIterator: PolymerLocationIterator.fromGroup,
|
||||
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
|
||||
getLoci: getPolymerElementLoci,
|
||||
eachLocation: eachPolymerElement,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerDirectionParams>, currentProps: PD.Values<PolymerDirectionParams>) => {
|
||||
|
||||
@@ -187,7 +187,7 @@ export function PolymerTraceVisual(materialId: number): UnitsVisual<PolymerTrace
|
||||
return UnitsMeshVisual<PolymerTraceParams>({
|
||||
defaultProps: PD.getDefaultValues(PolymerTraceParams),
|
||||
createGeometry: createPolymerTraceMesh,
|
||||
createLocationIterator: sg => PolymerLocationIterator.fromGroup(sg, true),
|
||||
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup, { asSecondary: true }),
|
||||
getLoci: getPolymerElementLoci,
|
||||
eachLocation: eachPolymerElement,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerTraceParams>, currentProps: PD.Values<PolymerTraceParams>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup) => {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Vec3 } from '../../../mol-math/linear-algebra';
|
||||
import { addSphere } from '../../../mol-geo/geometry/mesh/builder/sphere';
|
||||
import { BaseGeometry } from '../../../mol-geo/geometry/base';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { StructureGroup } from './util/common';
|
||||
|
||||
export const PolymerTubeMeshParams = {
|
||||
sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
|
||||
@@ -117,7 +118,7 @@ export function PolymerTubeVisual(materialId: number): UnitsVisual<PolymerTubePa
|
||||
return UnitsMeshVisual<PolymerTubeParams>({
|
||||
defaultProps: PD.getDefaultValues(PolymerTubeParams),
|
||||
createGeometry: createPolymerTubeMesh,
|
||||
createLocationIterator: sg => PolymerLocationIterator.fromGroup(sg, true),
|
||||
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup, { asSecondary: true }),
|
||||
getLoci: getPolymerElementLoci,
|
||||
eachLocation: eachPolymerElement,
|
||||
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerTubeParams>, currentProps: PD.Values<PolymerTubeParams>) => {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { BondType } from '../../../../mol-model/structure/model/types';
|
||||
@@ -125,7 +126,7 @@ export function makeInterBondIgnoreTest(structure: Structure, props: BondProps):
|
||||
}
|
||||
|
||||
export namespace BondIterator {
|
||||
export function fromGroup(structureGroup: StructureGroup): LocationIterator {
|
||||
export function fromGroup(structureGroup: StructureGroup, props?: { includeLocation2?: boolean }): LocationIterator {
|
||||
const { group, structure } = structureGroup;
|
||||
const unit = group.units[0] as Unit.Atomic;
|
||||
const groupCount = Unit.isAtomic(unit) ? unit.bonds.edgeCount * 2 : 0;
|
||||
@@ -139,10 +140,22 @@ export namespace BondIterator {
|
||||
location.bIndex = unit.bonds.b[groupIndex];
|
||||
return location;
|
||||
};
|
||||
if (props?.includeLocation2) {
|
||||
const location2 = Bond.Location(structure, undefined, undefined, structure, undefined, undefined);
|
||||
const getLocation2 = (groupIndex: number, instanceIndex: number) => { // swapping A and B
|
||||
const unit = group.units[instanceIndex] as Unit.Atomic;
|
||||
location2.aUnit = unit;
|
||||
location2.bUnit = unit;
|
||||
location2.aIndex = unit.bonds.b[groupIndex];
|
||||
location2.bIndex = unit.bonds.a[groupIndex];
|
||||
return location2;
|
||||
};
|
||||
return LocationIterator(groupCount, instanceCount, 1, getLocation, false, () => false, getLocation2);
|
||||
}
|
||||
return LocationIterator(groupCount, instanceCount, 1, getLocation);
|
||||
}
|
||||
|
||||
export function fromStructure(structure: Structure): LocationIterator {
|
||||
export function fromStructure(structure: Structure, props?: { includeLocation2?: boolean }): LocationIterator {
|
||||
const groupCount = structure.interUnitBonds.edgeCount;
|
||||
const instanceCount = 1;
|
||||
const location = Bond.Location(structure, undefined, undefined, structure, undefined, undefined);
|
||||
@@ -154,6 +167,18 @@ export namespace BondIterator {
|
||||
location.bIndex = bond.indexB;
|
||||
return location;
|
||||
};
|
||||
if (props?.includeLocation2) {
|
||||
const location2 = Bond.Location(structure, undefined, undefined, structure, undefined, undefined);
|
||||
const getLocation2 = (groupIndex: number) => { // swapping A and B
|
||||
const bond = structure.interUnitBonds.edges[groupIndex];
|
||||
location2.aUnit = structure.unitMap.get(bond.unitB);
|
||||
location2.aIndex = bond.indexB;
|
||||
location2.bUnit = structure.unitMap.get(bond.unitA);
|
||||
location2.bIndex = bond.indexA;
|
||||
return location2;
|
||||
};
|
||||
return LocationIterator(groupCount, instanceCount, 1, getLocation, true, () => false, getLocation2);
|
||||
};
|
||||
return LocationIterator(groupCount, instanceCount, 1, getLocation, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ export const LinkCylinderParams = {
|
||||
dashCap: PD.Boolean(true),
|
||||
stubCap: PD.Boolean(true),
|
||||
radialSegments: PD.Numeric(16, { min: 2, max: 56, step: 2 }, BaseGeometry.CustomQualityParamInfo),
|
||||
colorMode: PD.Select('default', PD.arrayToOptions(['default', 'interpolate'] as const), BaseGeometry.ShadingCategory)
|
||||
};
|
||||
export const DefaultLinkCylinderProps = PD.getDefaultValues(LinkCylinderParams);
|
||||
export type LinkCylinderProps = typeof DefaultLinkCylinderProps
|
||||
@@ -264,7 +265,9 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
||||
|
||||
if (!linkCount) return { cylinders: Cylinders.createEmpty(cylinders) };
|
||||
|
||||
const { linkScale, linkSpacing, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap } = props;
|
||||
const { linkScale, linkSpacing, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap, colorMode } = props;
|
||||
const interpolate = colorMode === 'interpolate';
|
||||
const colorModeFlag = interpolate === true ? 3 : 2;
|
||||
|
||||
const cylindersCountEstimate = linkCount * 2;
|
||||
const builder = CylindersBuilder.create(cylindersCountEstimate, cylindersCountEstimate / 4, cylinders);
|
||||
@@ -292,10 +295,10 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
||||
|
||||
if (linkStyle === LinkStyle.Solid) {
|
||||
v3scale(vm, v3add(vm, va, vb), 0.5);
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, colorModeFlag, edgeIndex);
|
||||
} else if (linkStyle === LinkStyle.Dashed) {
|
||||
v3scale(vm, v3add(vm, va, vb), 0.5);
|
||||
builder.addFixedCountDashes(va, vm, dashCount, dashScale, dashCap, dashCap, linkStub, edgeIndex);
|
||||
builder.addFixedCountDashes(va, vm, dashCount, dashScale, dashCap, dashCap, linkStub, interpolate, edgeIndex);
|
||||
} else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
||||
const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 :
|
||||
(linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5;
|
||||
@@ -306,7 +309,7 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
||||
calculateShiftDir(vShift, va, vb, referencePosition ? referencePosition(edgeIndex) : null);
|
||||
|
||||
if (linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, colorModeFlag, edgeIndex);
|
||||
|
||||
const aromaticOffset = linkRadius + aromaticScale * linkRadius + aromaticScale * linkRadius * aromaticSpacing;
|
||||
|
||||
@@ -316,38 +319,38 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
||||
v3setMagnitude(vShift, vShift, aromaticOffset);
|
||||
v3sub(va, va, vShift);
|
||||
v3sub(vm, vm, vShift);
|
||||
builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, edgeIndex);
|
||||
builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, interpolate, edgeIndex);
|
||||
|
||||
if (linkStyle === LinkStyle.MirroredAromatic) {
|
||||
v3setMagnitude(vShift, vShift, aromaticOffset * 2);
|
||||
v3add(va, va, vShift);
|
||||
v3add(vm, vm, vShift);
|
||||
builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, edgeIndex);
|
||||
builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, interpolate, edgeIndex);
|
||||
}
|
||||
} else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
|
||||
const multipleOffset = linkRadius + multiScale * linkRadius + linkScale * linkRadius * linkSpacing;
|
||||
v3setMagnitude(vShift, vShift, multipleOffset);
|
||||
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, colorModeFlag, edgeIndex);
|
||||
|
||||
v3setMagnitude(tmpV12, v3sub(tmpV12, va, vm), linkRadius / 1.5);
|
||||
v3sub(va, va, tmpV12);
|
||||
|
||||
if (order === 3) builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, edgeIndex);
|
||||
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, dashCap, linkStub, edgeIndex);
|
||||
if (order === 3) builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, colorModeFlag, edgeIndex);
|
||||
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, dashCap, linkStub, colorModeFlag, edgeIndex);
|
||||
} else {
|
||||
v3setMagnitude(vShift, vShift, absOffset);
|
||||
|
||||
if (order === 3) builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], multiScale, linkCap, linkStub, edgeIndex);
|
||||
builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, edgeIndex);
|
||||
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, linkCap, linkStub, edgeIndex);
|
||||
if (order === 3) builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], multiScale, linkCap, linkStub, colorModeFlag, edgeIndex);
|
||||
builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, colorModeFlag, edgeIndex);
|
||||
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, linkCap, linkStub, colorModeFlag, edgeIndex);
|
||||
}
|
||||
} else if (linkStyle === LinkStyle.Disk) {
|
||||
v3scale(tmpV12, v3sub(tmpV12, vm, va), 0.475);
|
||||
v3add(va, va, tmpV12);
|
||||
v3sub(vm, vm, tmpV12);
|
||||
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
||||
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, colorModeFlag, edgeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ export function getGapRanges(unit: Unit): SortedRanges<ElementIndex> {
|
||||
}
|
||||
|
||||
export namespace PolymerLocationIterator {
|
||||
export function fromGroup(structureGroup: StructureGroup, asSecondary = false): LocationIterator {
|
||||
export function fromGroup(structureGroup: StructureGroup, options?: { asSecondary?: boolean }): LocationIterator {
|
||||
const { group, structure } = structureGroup;
|
||||
const polymerElements = group.units[0].polymerElements;
|
||||
const groupCount = polymerElements.length;
|
||||
@@ -53,6 +53,7 @@ export namespace PolymerLocationIterator {
|
||||
location.element = polymerElements[groupIndex];
|
||||
return location;
|
||||
};
|
||||
const asSecondary = !!options?.asSecondary;
|
||||
function isSecondary(elementIndex: number, instanceIndex: number) {
|
||||
return asSecondary;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
@@ -104,10 +104,13 @@ export namespace ParamDefinition {
|
||||
}
|
||||
|
||||
export interface Text<T extends string = string> extends Base<T> {
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
multiline?: boolean,
|
||||
placeholder?: string,
|
||||
disableInteractiveUpdates?: boolean
|
||||
}
|
||||
export function Text<T extends string = string>(defaultValue: string = '', info?: Info): Text<T> {
|
||||
return setInfo<Text<T>>({ type: 'text', defaultValue: defaultValue as any }, info);
|
||||
export function Text<T extends string = string>(defaultValue: string = '', info?: Info & { multiline?: boolean, placeholder?: string, disableInteractiveUpdates?: boolean }): Text<T> {
|
||||
return setInfo<Text<T>>({ type: 'text', defaultValue: defaultValue as any, multiline: info?.multiline, placeholder: info?.placeholder, disableInteractiveUpdates: info?.disableInteractiveUpdates }, info);
|
||||
}
|
||||
|
||||
export interface Color extends Base<ColorData> {
|
||||
|
||||
Reference in New Issue
Block a user