mirror of
https://github.com/molstar/molstar.git
synced 2026-06-05 14:04:36 +08:00
Compare commits
6 Commits
v2.0.0-dev
...
v2.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d527609b6d | ||
|
|
e628f580a7 | ||
|
|
b662179b4d | ||
|
|
fa2b8542bf | ||
|
|
901522f500 | ||
|
|
62b63c1aa5 |
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "2.0.0-dev.1",
|
||||
"version": "2.0.0-dev.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "1.2.15",
|
||||
"version": "2.0.0-dev.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/argparse": "^1.0.38",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "2.0.0-dev.1",
|
||||
"version": "2.0.0-dev.3",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
|
||||
@@ -12,18 +12,18 @@
|
||||
}
|
||||
#app {
|
||||
position: absolute;
|
||||
left: 160px;
|
||||
top: 100px;
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
border: 1px solid #ccc;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position: absolute;
|
||||
width: 150px;
|
||||
top: 100px;
|
||||
left: 780px;
|
||||
bottom: 100px;
|
||||
right: 50px;
|
||||
z-index: 10;
|
||||
font-family: sans-serif;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
#controls > button {
|
||||
@@ -46,13 +46,13 @@
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
LightingDemo.init('app')
|
||||
LightingDemo.load({ url: 'https://files.rcsb.org/download/1M07.cif', assemblyId: '1' })
|
||||
LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3)
|
||||
|
||||
addHeader('Example PDB IDs');
|
||||
addControl('1M07', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/1M07.cif', assemblyId: '1' }));
|
||||
addControl('6HY0', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/6HY0.cif', assemblyId: '1' }));
|
||||
addControl('6QVK', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/6QVK.cif', assemblyId: '1' }));
|
||||
addControl('1RB8', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/1RB8.cif', assemblyId: '1' }));
|
||||
addControl('4KTC', () => LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3));
|
||||
addControl('5FJ5', () => LightingDemo.load({ url: 'https://models.rcsb.org/5FJ5.bcif', assemblyId: '1' }, 8, 1.8));
|
||||
addControl('1UPN', () => LightingDemo.load({ url: 'https://models.rcsb.org/1UPN.bcif', assemblyId: '1' }, 7, 1.6));
|
||||
addControl('1RB8', () => LightingDemo.load({ url: 'https://models.rcsb.org/1RB8.bcif', assemblyId: '1' }, 6, 1.3));
|
||||
|
||||
addSeparator()
|
||||
|
||||
|
||||
@@ -25,12 +25,11 @@ const Canvas3DPresets = {
|
||||
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
|
||||
},
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 64, radius: 8, bias: 1.0, blurKernelSize: 13 } },
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.33 } }
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.1 } }
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 1,
|
||||
lightIntensity: 0,
|
||||
style: { name: 'flat', params: {} }
|
||||
}
|
||||
},
|
||||
occlusion: <Preset> {
|
||||
@@ -38,12 +37,11 @@ const Canvas3DPresets = {
|
||||
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
|
||||
},
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 64, radius: 8, bias: 1.0, blurKernelSize: 13 } },
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
|
||||
outline: { name: 'off', params: { } }
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 0.4,
|
||||
lightIntensity: 0.6,
|
||||
style: { name: 'matte', params: {} }
|
||||
}
|
||||
},
|
||||
standard: <Preset> {
|
||||
@@ -55,17 +53,21 @@ const Canvas3DPresets = {
|
||||
outline: { name: 'off', params: { } }
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 0.4,
|
||||
lightIntensity: 0.6,
|
||||
style: { name: 'matte', params: {} }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
type Canvas3DPreset = keyof typeof Canvas3DPresets
|
||||
|
||||
class LightingDemo {
|
||||
plugin: PluginContext;
|
||||
|
||||
private radius = 5;
|
||||
private bias = 1.1;
|
||||
private preset: Canvas3DPreset = 'illustrative';
|
||||
|
||||
init(target: string | HTMLElement) {
|
||||
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...DefaultPluginSpec(),
|
||||
@@ -83,6 +85,10 @@ class LightingDemo {
|
||||
|
||||
setPreset(preset: Canvas3DPreset) {
|
||||
const props = Canvas3DPresets[preset];
|
||||
if (props.postprocessing.occlusion?.name === 'on') {
|
||||
props.postprocessing.occlusion.params.radius = this.radius;
|
||||
props.postprocessing.occlusion.params.bias = this.bias;
|
||||
}
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
|
||||
...props,
|
||||
multiSample: {
|
||||
@@ -100,7 +106,7 @@ class LightingDemo {
|
||||
}});
|
||||
}
|
||||
|
||||
async load({ url, format = 'mmcif', isBinary = false, assemblyId = '' }: LoadParams) {
|
||||
async load({ url, format = 'mmcif', isBinary = true, assemblyId = '' }: LoadParams, radius: number, bias: number) {
|
||||
await this.plugin.clear();
|
||||
|
||||
const data = await this.plugin.builders.data.download({ url: Asset.Url(url), isBinary }, { state: { isGhost: true } });
|
||||
@@ -112,7 +118,11 @@ class LightingDemo {
|
||||
if (polymer) await this.plugin.builders.structure.representation.addRepresentation(polymer, { type: 'spacefill', color: 'illustrative' });
|
||||
|
||||
const ligand = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'ligand');
|
||||
if (ligand) await this.plugin.builders.structure.representation.addRepresentation(ligand, { type: 'ball-and-stick' });
|
||||
if (ligand) await this.plugin.builders.structure.representation.addRepresentation(ligand, { type: 'ball-and-stick', color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } });
|
||||
|
||||
this.radius = radius;
|
||||
this.bias = bias;
|
||||
this.setPreset(this.preset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import { quad_vert } from '../../../mol-gl/shader/quad.vert';
|
||||
import { isosurface_frag } from '../../../mol-gl/shader/marching-cubes/isosurface.frag';
|
||||
import { calcActiveVoxels } from './active-voxels';
|
||||
import { isWebGL2 } from '../../webgl/compat';
|
||||
import { Scheduler } from '../../../mol-task';
|
||||
|
||||
const IsosurfaceSchema = {
|
||||
...QuadSchema,
|
||||
@@ -185,26 +186,36 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
renderable.render();
|
||||
|
||||
gl.flush();
|
||||
gl.finish();
|
||||
|
||||
return { vertexTexture, groupTexture, normalTexture, vertexCount: count };
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
|
||||
function delay() {
|
||||
return new Promise(r => Scheduler.setImmediate(r));
|
||||
}
|
||||
|
||||
export async function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
|
||||
// console.time('calcActiveVoxels');
|
||||
const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale);
|
||||
// ctx.waitForGpuCommandsCompleteSync();
|
||||
// console.timeEnd('calcActiveVoxels');
|
||||
// apply advanced magic to solve incomplete buffer rendering issue
|
||||
await delay();
|
||||
|
||||
// console.time('createHistogramPyramid');
|
||||
const compacted = createHistogramPyramid(ctx, activeVoxelsTex, gridTexScale, gridTexDim);
|
||||
// apply advanced magic to solve incomplete buffer rendering issue
|
||||
await delay();
|
||||
|
||||
// ctx.waitForGpuCommandsCompleteSync();
|
||||
// console.timeEnd('createHistogramPyramid');
|
||||
|
||||
// console.time('createIsosurfaceBuffers');
|
||||
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, packedGroup, vertexTexture, groupTexture, normalTexture);
|
||||
// apply advanced magic to solve incomplete buffer rendering issue
|
||||
await delay();
|
||||
|
||||
// ctx.waitForGpuCommandsCompleteSync();
|
||||
// console.timeEnd('createIsosurfaceBuffers');
|
||||
|
||||
|
||||
@@ -383,10 +383,10 @@ export class SequenceView extends PluginUIComponent<{ defaultMode?: SequenceView
|
||||
|
||||
if (values.mode === 'single') return elem;
|
||||
|
||||
return <>
|
||||
return <React.Fragment key={i}>
|
||||
<div className='msp-sequence-chain-label'>{s.label}</div>
|
||||
{elem}
|
||||
</>;
|
||||
</React.Fragment>;
|
||||
})}
|
||||
</NonEmptySequenceWrapper>
|
||||
</div>;
|
||||
|
||||
@@ -181,7 +181,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit,
|
||||
|
||||
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
|
||||
|
||||
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
const gv = await extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
|
||||
const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
|
||||
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
|
||||
@@ -238,7 +238,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str
|
||||
|
||||
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
|
||||
|
||||
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
const gv = await extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
|
||||
const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
|
||||
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
|
||||
|
||||
@@ -175,7 +175,7 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol
|
||||
|
||||
const { texture, gridDimension, gridTexDim, gridTexScale, transform } = VolumeIsosurfaceTexture.get(volume, ctx.webgl);
|
||||
|
||||
const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, false, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
const gv = await extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, false, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
|
||||
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -33,6 +33,8 @@ import { OccupancyColorThemeProvider } from './color/occupancy';
|
||||
import { OperatorNameColorThemeProvider } from './color/operator-name';
|
||||
import { OperatorHklColorThemeProvider } from './color/operator-hkl';
|
||||
import { PartialChargeColorThemeProvider } from './color/partial-charge';
|
||||
import { AtomIdColorThemeProvider } from './color/atom-id';
|
||||
import { EntityIdColorThemeProvider } from './color/entity-id';
|
||||
|
||||
export type LocationColor = (location: Location, isSecondary: boolean) => Color
|
||||
|
||||
@@ -80,10 +82,12 @@ namespace ColorTheme {
|
||||
}
|
||||
|
||||
export const BuiltIn = {
|
||||
'atom-id': AtomIdColorThemeProvider,
|
||||
'carbohydrate-symbol': CarbohydrateSymbolColorThemeProvider,
|
||||
'chain-id': ChainIdColorThemeProvider,
|
||||
'element-index': ElementIndexColorThemeProvider,
|
||||
'element-symbol': ElementSymbolColorThemeProvider,
|
||||
'entity-id': EntityIdColorThemeProvider,
|
||||
'entity-source': EntitySourceColorThemeProvider,
|
||||
'hydrophobicity': HydrophobicityColorThemeProvider,
|
||||
'illustrative': IllustrativeColorThemeProvider,
|
||||
|
||||
90
src/mol-theme/color/atom-id.ts
Normal file
90
src/mol-theme/color/atom-id.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { StructureProperties, StructureElement, Bond, Structure } from '../../mol-model/structure';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { Location } from '../../mol-model/location';
|
||||
import { ColorTheme, LocationColor } from '../color';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { ThemeDataContext } from '../../mol-theme/theme';
|
||||
import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
|
||||
import { TableLegend, ScaleLegend } from '../../mol-util/legend';
|
||||
|
||||
const DefaultList = 'many-distinct';
|
||||
const DefaultColor = Color(0xFAFAFA);
|
||||
const Description = 'Gives every atom a color based on its `label_atom_id` value.';
|
||||
|
||||
export const AtomIdColorThemeParams = {
|
||||
...getPaletteParams({ type: 'colors', colorList: DefaultList }),
|
||||
};
|
||||
export type AtomIdColorThemeParams = typeof AtomIdColorThemeParams
|
||||
export function getAtomIdColorThemeParams(ctx: ThemeDataContext) {
|
||||
const params = PD.clone(AtomIdColorThemeParams);
|
||||
return params;
|
||||
}
|
||||
|
||||
function getAtomIdSerialMap(structure: Structure) {
|
||||
const map = new Map<string, number>();
|
||||
for (const m of structure.models) {
|
||||
const { label_atom_id } = m.atomicHierarchy.atoms;
|
||||
for (let i = 0, il = label_atom_id.rowCount; i < il; ++i) {
|
||||
const id = label_atom_id.value(i);
|
||||
if (!map.has(id)) map.set(id, map.size);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export function AtomIdColorTheme(ctx: ThemeDataContext, props: PD.Values<AtomIdColorThemeParams>): ColorTheme<AtomIdColorThemeParams> {
|
||||
let color: LocationColor;
|
||||
let legend: ScaleLegend | TableLegend | undefined;
|
||||
|
||||
if (ctx.structure) {
|
||||
const l = StructureElement.Location.create(ctx.structure.root);
|
||||
const atomIdSerialMap = getAtomIdSerialMap(ctx.structure.root);
|
||||
|
||||
const labelTable = Array.from(atomIdSerialMap.keys());
|
||||
const valueLabel = (i: number) => labelTable[i];
|
||||
|
||||
const palette = getPalette(atomIdSerialMap.size, props, { valueLabel });
|
||||
legend = palette.legend;
|
||||
|
||||
color = (location: Location): Color => {
|
||||
let serial: number | undefined = undefined;
|
||||
if (StructureElement.Location.is(location)) {
|
||||
const id = StructureProperties.atom.label_atom_id(location);
|
||||
serial = atomIdSerialMap.get(id);
|
||||
} else if (Bond.isLocation(location)) {
|
||||
l.unit = location.aUnit;
|
||||
l.element = location.aUnit.elements[location.aIndex];
|
||||
const id = StructureProperties.atom.label_atom_id(l);
|
||||
serial = atomIdSerialMap.get(id);
|
||||
}
|
||||
return serial === undefined ? DefaultColor : palette.color(serial);
|
||||
};
|
||||
} else {
|
||||
color = () => DefaultColor;
|
||||
}
|
||||
|
||||
return {
|
||||
factory: AtomIdColorTheme,
|
||||
granularity: 'group',
|
||||
color,
|
||||
props,
|
||||
description: Description,
|
||||
legend
|
||||
};
|
||||
}
|
||||
|
||||
export const AtomIdColorThemeProvider: ColorTheme.Provider<AtomIdColorThemeParams, 'atom-id'> = {
|
||||
name: 'atom-id',
|
||||
label: 'Atom Id',
|
||||
category: ColorTheme.Category.Atom,
|
||||
factory: AtomIdColorTheme,
|
||||
getParams: getAtomIdColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(AtomIdColorThemeParams),
|
||||
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
|
||||
};
|
||||
98
src/mol-theme/color/entity-id.ts
Normal file
98
src/mol-theme/color/entity-id.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { StructureProperties, StructureElement, Bond, Structure } from '../../mol-model/structure';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { Location } from '../../mol-model/location';
|
||||
import { ColorTheme, LocationColor } from '../color';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { ThemeDataContext } from '../../mol-theme/theme';
|
||||
import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
|
||||
import { TableLegend, ScaleLegend } from '../../mol-util/legend';
|
||||
|
||||
const DefaultList = 'many-distinct';
|
||||
const DefaultColor = Color(0xFAFAFA);
|
||||
const Description = 'Gives every chain a color based on its `label_entity_id` value.';
|
||||
|
||||
export const EntityIdColorThemeParams = {
|
||||
...getPaletteParams({ type: 'colors', colorList: DefaultList }),
|
||||
};
|
||||
export type EntityIdColorThemeParams = typeof EntityIdColorThemeParams
|
||||
export function getEntityIdColorThemeParams(ctx: ThemeDataContext) {
|
||||
const params = PD.clone(EntityIdColorThemeParams);
|
||||
return params;
|
||||
}
|
||||
|
||||
function key(entityId: string, modelIndex: number) {
|
||||
return `${entityId}|${modelIndex}`;
|
||||
}
|
||||
|
||||
function getEntityIdSerialMap(structure: Structure) {
|
||||
const map = new Map<string, number>();
|
||||
for (let i = 0, il = structure.models.length; i < il; ++i) {
|
||||
const { label_entity_id } = structure.models[i].atomicHierarchy.chains;
|
||||
for (let j = 0, jl = label_entity_id.rowCount; j < jl; ++j) {
|
||||
const k = key(label_entity_id.value(j), i);
|
||||
if (!map.has(k)) map.set(k, map.size);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export function EntityIdColorTheme(ctx: ThemeDataContext, props: PD.Values<EntityIdColorThemeParams>): ColorTheme<EntityIdColorThemeParams> {
|
||||
let color: LocationColor;
|
||||
let legend: ScaleLegend | TableLegend | undefined;
|
||||
|
||||
if (ctx.structure) {
|
||||
const l = StructureElement.Location.create(ctx.structure.root);
|
||||
const entityIdSerialMap = getEntityIdSerialMap(ctx.structure.root);
|
||||
|
||||
const labelTable = Array.from(entityIdSerialMap.keys());
|
||||
const valueLabel = (i: number) => labelTable[i];
|
||||
|
||||
const palette = getPalette(entityIdSerialMap.size, props, { valueLabel });
|
||||
legend = palette.legend;
|
||||
|
||||
color = (location: Location): Color => {
|
||||
let serial: number | undefined = undefined;
|
||||
if (StructureElement.Location.is(location)) {
|
||||
const atomId = StructureProperties.chain.label_entity_id(location);
|
||||
const modelIndex = location.structure.models.indexOf(location.unit.model);
|
||||
const k = key(atomId, modelIndex);
|
||||
serial = entityIdSerialMap.get(k);
|
||||
} else if (Bond.isLocation(location)) {
|
||||
l.unit = location.aUnit;
|
||||
l.element = location.aUnit.elements[location.aIndex];
|
||||
const atomId = StructureProperties.chain.label_entity_id(l);
|
||||
const modelIndex = l.structure.models.indexOf(l.unit.model);
|
||||
const k = key(atomId, modelIndex);
|
||||
serial = entityIdSerialMap.get(k);
|
||||
}
|
||||
return serial === undefined ? DefaultColor : palette.color(serial);
|
||||
};
|
||||
} else {
|
||||
color = () => DefaultColor;
|
||||
}
|
||||
|
||||
return {
|
||||
factory: EntityIdColorTheme,
|
||||
granularity: 'group',
|
||||
color,
|
||||
props,
|
||||
description: Description,
|
||||
legend
|
||||
};
|
||||
}
|
||||
|
||||
export const EntityIdColorThemeProvider: ColorTheme.Provider<EntityIdColorThemeParams, 'entity-id'> = {
|
||||
name: 'entity-id',
|
||||
label: 'Entity Id',
|
||||
category: ColorTheme.Category.Chain,
|
||||
factory: EntityIdColorTheme,
|
||||
getParams: getEntityIdColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(EntityIdColorThemeParams),
|
||||
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
|
||||
};
|
||||
Reference in New Issue
Block a user