mirror of
https://github.com/molstar/molstar.git
synced 2026-06-07 23:34:23 +08:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d2e4115ed | ||
|
|
dbce1ccb3d | ||
|
|
03aa2be978 | ||
|
|
8dfc52e1ab | ||
|
|
6058179f10 | ||
|
|
ea9e25b03c | ||
|
|
d60c3ddce3 | ||
|
|
724e79bddf | ||
|
|
2de61215c4 | ||
|
|
e783d9a9f1 | ||
|
|
e9e971d4f3 | ||
|
|
96dea14cb1 | ||
|
|
04fc157340 | ||
|
|
cfc24fa99e |
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "1.2.8",
|
||||
"version": "1.2.9",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "1.2.8",
|
||||
"version": "1.2.9",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/argparse": "^1.0.38",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "1.2.8",
|
||||
"version": "1.2.9",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
|
||||
@@ -19,6 +19,7 @@ import { Theme } from '../../mol-theme/theme';
|
||||
import { VolumeRepresentation3DHelpers } from '../../mol-plugin-state/transforms/representation';
|
||||
import { AlphaOrbital, Basis, CubeGrid } from './data-model';
|
||||
import { createSphericalCollocationDensityGrid } from './density';
|
||||
import { Tensor } from '../../mol-math/linear-algebra';
|
||||
|
||||
export class BasisAndOrbitals extends PluginStateObject.Create<{ basis: Basis, order: SphericalBasisOrder, orbitals: AlphaOrbital[] }>({ name: 'Basis', typeClass: 'Object' }) { }
|
||||
|
||||
@@ -49,9 +50,43 @@ const CreateOrbitalVolumeParamBase = {
|
||||
{ atomCount: 25, spacing: 0.4 },
|
||||
{ atomCount: 0, spacing: 0.35 },
|
||||
]
|
||||
}),
|
||||
clampValues: PD.MappedStatic('off', {
|
||||
off: PD.EmptyGroup(),
|
||||
on: PD.Group({
|
||||
sigma: PD.Numeric(8, { min: 1, max: 20 }, { description: 'Clamp values to range [sigma * negIsoValue, sigma * posIsoValue].' })
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
function clampData(matrix: Tensor.Data, min: number, max: number) {
|
||||
for (let i = 0, _i = matrix.length; i < _i; i++) {
|
||||
const v = matrix[i];
|
||||
if (v < min) matrix[i] = min;
|
||||
else if (v > max) matrix[i] = max;
|
||||
}
|
||||
}
|
||||
|
||||
function clampGrid(data: CubeGrid, v: number) {
|
||||
const grid = data.grid;
|
||||
const min = (data.isovalues?.negative ?? data.grid.stats.min) * v;
|
||||
const max = (data.isovalues?.positive ?? data.grid.stats.max) * v;
|
||||
|
||||
// clamp values for better direct volume resolution
|
||||
// current implementation uses Byte array for values
|
||||
// if this is not enough, update mol* to use float
|
||||
// textures instead
|
||||
if (grid.stats.min < min || grid.stats.max > max) {
|
||||
clampData(data.grid.cells.data, min, max);
|
||||
if (grid.stats.min < min) {
|
||||
(grid.stats.min as number) = min;
|
||||
}
|
||||
if (grid.stats.max > max) {
|
||||
(grid.stats.max as number) = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const CreateOrbitalVolume = PluginStateTransform.BuiltIn({
|
||||
name: 'create-orbital-volume',
|
||||
display: 'Orbital Volume',
|
||||
@@ -84,6 +119,10 @@ export const CreateOrbitalVolume = PluginStateTransform.BuiltIn({
|
||||
_propertyData: Object.create(null),
|
||||
};
|
||||
|
||||
if (params.clampValues?.name === 'on') {
|
||||
clampGrid(data, params.clampValues?.params?.sigma ?? 8);
|
||||
}
|
||||
|
||||
return new PluginStateObject.Volume.Data(volume, { label: 'Orbital Volume' });
|
||||
});
|
||||
}
|
||||
@@ -112,6 +151,10 @@ export const CreateOrbitalDensityVolume = PluginStateTransform.BuiltIn({
|
||||
_propertyData: Object.create(null),
|
||||
};
|
||||
|
||||
if (params.clampValues?.name === 'on') {
|
||||
clampGrid(data, params.clampValues?.params?.sigma ?? 8);
|
||||
}
|
||||
|
||||
return new PluginStateObject.Volume.Data(volume, { label: 'Orbital Volume' });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -377,9 +377,16 @@ export class SequenceView extends PluginUIComponent<{ defaultMode?: SequenceView
|
||||
|
||||
<NonEmptySequenceWrapper>
|
||||
{sequenceWrappers.map((s, i) => {
|
||||
return typeof s.wrapper === 'string'
|
||||
const elem = typeof s.wrapper === 'string'
|
||||
? <div key={i} className='msp-sequence-wrapper'>{s.wrapper}</div>
|
||||
: <Sequence key={i} sequenceWrapper={s.wrapper} label={values.mode === 'single' ? void 0 : s.label} />;
|
||||
: <Sequence key={i} sequenceWrapper={s.wrapper} />;
|
||||
|
||||
if (values.mode === 'single') return elem;
|
||||
|
||||
return <>
|
||||
<div className='msp-sequence-chain-label'>{s.label}</div>
|
||||
{elem}
|
||||
</>;
|
||||
})}
|
||||
</NonEmptySequenceWrapper>
|
||||
</div>;
|
||||
|
||||
@@ -20,7 +20,6 @@ type SequenceProps = {
|
||||
sequenceWrapper: SequenceWrapper.Any,
|
||||
sequenceNumberPeriod?: number,
|
||||
hideSequenceNumbers?: boolean,
|
||||
label?: string
|
||||
}
|
||||
|
||||
/** Note, if this is changed, the CSS for `msp-sequence-number` needs adjustment too */
|
||||
@@ -301,7 +300,6 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
|
||||
onMouseLeave={this.mouseLeave}
|
||||
ref={this.parentDiv}
|
||||
>
|
||||
{this.props.label && <div className='msp-sequence-label'>{this.props.label}</div>}
|
||||
{elems}
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,16 @@ $sequence-select-height: 24px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.msp-sequence-chain-label {
|
||||
margin-left: $control-spacing;
|
||||
margin-top: $control-spacing;
|
||||
user-select: none;
|
||||
color: $sequence-number-color;
|
||||
font-size: 90%;
|
||||
line-height: 90%;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
|
||||
.msp-sequence-wrapper {
|
||||
span {
|
||||
cursor: pointer;
|
||||
@@ -81,7 +91,7 @@ $sequence-select-height: 24px;
|
||||
padding-bottom: 1em;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
|
||||
|
||||
.msp-sequence-number {
|
||||
color: $sequence-number-color;
|
||||
word-break: keep-all;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# 0.9.6
|
||||
* optional download parameter
|
||||
|
||||
# 0.9.5
|
||||
* Support molstar_global_model_transform_info category.
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ export interface MultipleQueryEntry<Name extends QueryName = QueryName> {
|
||||
export interface MultipleQuerySpec {
|
||||
queries: MultipleQueryEntry[],
|
||||
encoding?: Encoding,
|
||||
asTarGz?: boolean
|
||||
asTarGz?: boolean,
|
||||
download?: boolean
|
||||
}
|
||||
|
||||
export function getMultiQuerySpecFilename() {
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as bodyParser from 'body-parser';
|
||||
import { ModelServerConfig as Config, ModelServerConfig, mapSourceAndIdToFilename } from '../config';
|
||||
import { ConsoleLogger } from '../../../mol-util/console-logger';
|
||||
import { resolveJob } from './query';
|
||||
import { JobManager, JobEntry } from './jobs';
|
||||
import { JobManager, JobEntry, ResultWriterParams } from './jobs';
|
||||
import { UUID } from '../../../mol-util';
|
||||
import { QueryDefinition, normalizeRestQueryParams, normalizeRestCommonParams, QueryList } from './api';
|
||||
import { getApiSchema, shortcutIconLink } from './api-schema';
|
||||
@@ -45,17 +45,18 @@ async function processNextJob() {
|
||||
}
|
||||
}
|
||||
|
||||
export function createResultWriter(response: express.Response, encoding: string, entryId?: string, queryName?: string) {
|
||||
const filenameBase = entryId && queryName
|
||||
? `${entryId}_${splitCamelCase(queryName.replace(/\s/g, '_'), '-').toLowerCase()}`
|
||||
export function createResultWriter(response: express.Response, params: ResultWriterParams) {
|
||||
const filenameBase = params.entryId && params.queryName
|
||||
? `${params.entryId}_${splitCamelCase(params.queryName.replace(/\s/g, '_'), '-').toLowerCase()}`
|
||||
: `result`;
|
||||
return new SimpleResponseResultWriter(`${filenameBase}.${encoding}`, response, encoding === 'bcif');
|
||||
return new SimpleResponseResultWriter(`${filenameBase}.${params.encoding}`, response, params.encoding === 'bcif', params.download);
|
||||
}
|
||||
|
||||
function mapQuery(app: express.Express, queryName: string, queryDefinition: QueryDefinition) {
|
||||
function createJob(queryParams: any, req: express.Request, res: express.Response) {
|
||||
const entryId = req.params.id;
|
||||
const commonParams = normalizeRestCommonParams(req.query);
|
||||
const resultWriterParams = { encoding: commonParams.encoding!, download: !!commonParams.download, entryId, queryName };
|
||||
const jobId = JobManager.add({
|
||||
entries: [JobEntry({
|
||||
sourceId: commonParams.data_source || ModelServerConfig.defaultSource,
|
||||
@@ -66,7 +67,7 @@ function mapQuery(app: express.Express, queryName: string, queryDefinition: Quer
|
||||
copyAllCategories: !!commonParams.copy_all_categories,
|
||||
transform: commonParams.transform
|
||||
})],
|
||||
writer: createResultWriter(res, commonParams.encoding!, entryId, queryName),
|
||||
writer: createResultWriter(res, resultWriterParams),
|
||||
options: { binary: commonParams.encoding === 'bcif', encoding: commonParams.encoding }
|
||||
});
|
||||
responseMap.set(jobId, res);
|
||||
@@ -122,7 +123,7 @@ function serveStatic(req: express.Request, res: express.Response) {
|
||||
function createMultiJob(spec: MultipleQuerySpec, res: express.Response) {
|
||||
const writer = spec.asTarGz
|
||||
? new TarballResponseResultWriter(getMultiQuerySpecFilename(), res)
|
||||
: createResultWriter(res, spec.encoding!);
|
||||
: createResultWriter(res, { encoding: spec.encoding!, download: !!spec.download });
|
||||
|
||||
if (spec.queries.length > ModelServerConfig.maxQueryManyQueries) {
|
||||
writer.doError(400, `query-many queries limit (${ModelServerConfig.maxQueryManyQueries}) exceeded.`);
|
||||
|
||||
@@ -48,7 +48,8 @@ export const CommonQueryParamsInfo: QueryParamInfo[] = [
|
||||
{ name: 'encoding', type: QueryParamType.String, defaultValue: 'cif', description: `Determines the output encoding (text based 'CIF' or binary 'BCIF'). Ligands can also be exported as 'SDF', 'MOL', or 'MOL2'.`, supportedValues: ['cif', 'bcif', 'sdf', 'mol', 'mol2'] },
|
||||
{ name: 'copy_all_categories', type: QueryParamType.Boolean, defaultValue: false, description: 'If true, copy all categories from the input file.' },
|
||||
{ name: 'data_source', type: QueryParamType.String, defaultValue: '', description: 'Allows to control how the provided data source ID maps to input file (as specified by the server instance config).' },
|
||||
{ name: 'transform', type: QueryParamType.String, description: `Transformation to apply to coordinates in '_atom_site'. Accepts a 4x4 transformation matrix, provided as array of 16 float values.` }
|
||||
{ name: 'transform', type: QueryParamType.String, description: `Transformation to apply to coordinates in '_atom_site'. Accepts a 4x4 transformation matrix, provided as array of 16 float values.` },
|
||||
{ name: 'download', type: QueryParamType.Boolean, defaultValue: false, description: 'If true, browser will download text files.' }
|
||||
];
|
||||
|
||||
export type Encoding = 'cif' | 'bcif' | 'sdf' | 'mol' | 'mol2';
|
||||
@@ -57,7 +58,8 @@ export interface CommonQueryParamsInfo {
|
||||
encoding?: Encoding,
|
||||
copy_all_categories?: boolean
|
||||
data_source?: string,
|
||||
transform?: Mat4
|
||||
transform?: Mat4,
|
||||
download?: boolean
|
||||
}
|
||||
|
||||
export const AtomSiteSchemaElement = {
|
||||
@@ -290,12 +292,20 @@ export function normalizeRestCommonParams(params: any): CommonQueryParamsInfo {
|
||||
return {
|
||||
model_nums: params.model_nums ? ('' + params.model_nums).split(',').map(n => n.trim()).filter(n => !!n).map(n => +n) : void 0,
|
||||
data_source: params.data_source,
|
||||
copy_all_categories: Boolean(params.copy_all_categories),
|
||||
copy_all_categories: isTrue(params.copy_all_categories),
|
||||
encoding: mapEncoding(('' + params.encoding).toLocaleLowerCase()),
|
||||
transform: params.transform ? ('' + params.transform).split(',').map(n => n.trim()).map(n => +n) as Mat4 : Mat4.identity()
|
||||
transform: params.transform ? ('' + params.transform).split(',').map(n => n.trim()).map(n => +n) as Mat4 : Mat4.identity(),
|
||||
download: isTrue(params.download)
|
||||
};
|
||||
}
|
||||
|
||||
function isTrue(val: any): boolean {
|
||||
const b = Boolean(val);
|
||||
if (!b) return false;
|
||||
if (typeof val === 'string') return val !== '0' && val.toLowerCase() !== 'false';
|
||||
return b;
|
||||
}
|
||||
|
||||
function mapEncoding(value: string) {
|
||||
switch (value) {
|
||||
case 'bcif':
|
||||
|
||||
@@ -56,6 +56,13 @@ interface JobEntryDefinition<Name extends QueryName> {
|
||||
transform?: Mat4
|
||||
}
|
||||
|
||||
export interface ResultWriterParams {
|
||||
encoding: Encoding,
|
||||
download: boolean,
|
||||
entryId?: string,
|
||||
queryName?: string
|
||||
}
|
||||
|
||||
export function JobEntry<Name extends QueryName>(definition: JobEntryDefinition<Name>): JobEntry {
|
||||
const queryDefinition = getQueryByName(definition.queryName);
|
||||
if (!queryDefinition) throw new Error(`Query '${definition.queryName}' is not supported.`);
|
||||
|
||||
@@ -48,10 +48,11 @@ export class SimpleResponseResultWriter implements WebResutlWriter {
|
||||
this.headerWritten = true;
|
||||
|
||||
this.res.writeHead(200, {
|
||||
// TODO there seems to be a bug in swagger-ui - front-end will freeze for cif delivered as text/plain (forcing binary is a hack to circumvent this)
|
||||
'Content-Type': this.isBinary ? 'application/octet-stream' : 'text/plain; charset=utf-8',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'X-Requested-With',
|
||||
'Content-Disposition': `inline; filename="${this.fn}"`
|
||||
'Content-Disposition': `${this.isDownload ? 'attachment' : 'inline'}; filename="${this.fn}"`
|
||||
});
|
||||
}
|
||||
|
||||
@@ -71,7 +72,7 @@ export class SimpleResponseResultWriter implements WebResutlWriter {
|
||||
this.ended = true;
|
||||
}
|
||||
|
||||
constructor(private fn: string, private res: express.Response, private isBinary: boolean) {
|
||||
constructor(private fn: string, private res: express.Response, private isBinary: boolean, private isDownload: boolean) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
export default '0.9.5';
|
||||
export default '0.9.6';
|
||||
Reference in New Issue
Block a user