diff --git a/package-lock.json b/package-lock.json index a6e919d8410914b5d76a52a8e4ad3b668941885d..539aec393ef4a81fe88c46bb79781f76eeceaac4 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index 2a8e33f0618a18dee2d3a64009f085d4f5e82f8b..eede657509d5f0454525f990cd395429c99582ee 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "@types/react-dom": "^16.0.9", "@types/webgl2": "0.0.4", "benchmark": "^2.1.4", + "circular-dependency-plugin": "^5.0.2", "cpx": "^1.5.0", "css-loader": "^1.0.1", "extra-watch-webpack-plugin": "^1.0.3", diff --git a/src/apps/canvas/app.ts b/src/apps/canvas/app.ts index 25b2b5aeba30cd47ab92d99e7fb7d5fcdb46b391..fc8e304edd25da52c0e3bbe3f34432e4f4b62356 100644 --- a/src/apps/canvas/app.ts +++ b/src/apps/canvas/app.ts @@ -12,6 +12,10 @@ import { CifBlock } from 'mol-io/reader/cif'; import { VolumeView } from './volume-view'; import { Ccp4File } from 'mol-io/reader/ccp4/schema'; import { Progress } from 'mol-task'; +import { ColorTheme } from 'mol-theme/color'; +import { SizeTheme } from 'mol-theme/size'; +import { StructureRepresentationRegistry } from 'mol-repr/structure/registry'; +import { VolumeRepresentationRegistry } from 'mol-repr/volume/registry'; export class App { canvas3d: Canvas3D @@ -23,6 +27,11 @@ export class App { structureLoaded: BehaviorSubject<StructureView | null> = new BehaviorSubject<StructureView | null>(null) volumeLoaded: BehaviorSubject<VolumeView | null> = new BehaviorSubject<VolumeView | null>(null) + colorThemeRegistry = new ColorTheme.Registry() + sizeThemeRegistry = new SizeTheme.Registry() + structureRepresentationRegistry = new StructureRepresentationRegistry() + volumeRepresentationRegistry = new VolumeRepresentationRegistry() + initViewer(_canvas: HTMLCanvasElement, _container: HTMLDivElement) { this.canvas = _canvas this.container = _container @@ -64,6 +73,14 @@ export class App { console.log(Progress.format(progress)) } + get reprCtx () { + return { + webgl: this.canvas3d.webgl, + colorThemeRegistry: this.colorThemeRegistry, + sizeThemeRegistry: this.sizeThemeRegistry + } + } + // async loadMmcif(cif: CifBlock, assemblyId?: string) { diff --git a/src/apps/canvas/assembly-symmetry.ts b/src/apps/canvas/assembly-symmetry.ts index f4cdb2888466a56c6f9babcc311ea010249714db..e43357c196bd3f16120d60250bd10f502ce5f4e0 100644 --- a/src/apps/canvas/assembly-symmetry.ts +++ b/src/apps/canvas/assembly-symmetry.ts @@ -66,10 +66,10 @@ export function getClusterColorTheme(symmetryId: number, assemblySymmetry: Assem const DefaultColor = Color(0xCCCCCC) const s = assemblySymmetry.db.rcsb_assembly_symmetry const symmetry = Table.pickRow(s, i => s.id.value(i) === symmetryId) - if (!symmetry) return { features: {}, granularity: 'uniform', color: () => DefaultColor } + if (!symmetry) return { granularity: 'uniform', color: () => DefaultColor, props: {} } const clusters = assemblySymmetry.getClusters(symmetryId) - if (!clusters._rowCount) return { features: {}, granularity: 'uniform', color: () => DefaultColor } + if (!clusters._rowCount) return { granularity: 'uniform', color: () => DefaultColor, props: {} } const clusterByMember = new Map<string, number>() for (let i = 0, il = clusters._rowCount; i < il; ++i) { @@ -83,7 +83,6 @@ export function getClusterColorTheme(symmetryId: number, assemblySymmetry: Assem const scale = ColorScale.create({ domain: [ 0, clusters._rowCount - 1 ] }) return { - features: {}, granularity: 'instance', color: (location: Location): Color => { if (StructureElement.isLocation(location)) { @@ -94,6 +93,7 @@ export function getClusterColorTheme(symmetryId: number, assemblySymmetry: Assem return cluster !== undefined ? scale.color(cluster) : DefaultColor } return DefaultColor - } + }, + props: {} } } \ No newline at end of file diff --git a/src/apps/canvas/component/representation.tsx b/src/apps/canvas/component/representation.tsx index 8bbdf8bae91586a7dd784220c1230b24e3b838d8..ab7e997086e69cd5131b3785f29ad547c3d48530 100644 --- a/src/apps/canvas/component/representation.tsx +++ b/src/apps/canvas/component/representation.tsx @@ -8,16 +8,14 @@ import * as React from 'react' import Canvas3D from 'mol-canvas3d/canvas3d'; import { App } from '../app'; import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { Representation } from 'mol-repr'; +import { Representation } from 'mol-repr/representation'; import { ParametersComponent } from 'mol-app/component/parameters'; -import { ColorTheme } from 'mol-theme/color'; -import { getColorThemeProps } from 'mol-geo/geometry/color-data'; -import { ColorThemeComponent } from 'mol-app/component/color-theme'; -export interface RepresentationComponentProps { +export interface RepresentationComponentProps<P extends PD.Params> { app: App canvas3d: Canvas3D - repr: Representation<PD.Params> + repr: Representation<P> + params: P } export interface RepresentationComponentState { @@ -26,13 +24,13 @@ export interface RepresentationComponentState { reprProps: Readonly<{}> } -export class RepresentationComponent extends React.Component<RepresentationComponentProps, RepresentationComponentState> { +export class RepresentationComponent<P extends PD.Params> extends React.Component<RepresentationComponentProps<P>, RepresentationComponentState> { - private stateFromRepr(repr: Representation<PD.Params>) { + private stateFromRepr(repr: Representation<P>) { return { - label: this.props.repr.label, - reprParams: this.props.repr.params, - reprProps: this.props.repr.props + label: repr.label, + reprParams: this.props.params, + reprProps: repr.props } } @@ -41,8 +39,7 @@ export class RepresentationComponent extends React.Component<RepresentationCompo } async onChange(k: string, v: any) { - const ctx = { webgl: this.props.canvas3d.webgl } - await this.props.app.runTask(this.props.repr.createOrUpdate(ctx, { [k]: v }).run( + await this.props.app.runTask(this.props.repr.createOrUpdate(this.props.app.reprCtx, { [k]: v }).run( progress => this.props.app.log(progress) ), 'Representation Update') this.props.canvas3d.add(this.props.repr) @@ -52,10 +49,10 @@ export class RepresentationComponent extends React.Component<RepresentationCompo render() { const { label, reprParams, reprProps } = this.state - let colorTheme: ColorTheme | undefined = undefined - if ('colorTheme' in reprProps) { - colorTheme = ColorTheme(getColorThemeProps(reprProps)) - } + // let colorTheme: ColorTheme | undefined = undefined + // if ('colorTheme' in reprProps) { + // colorTheme = ColorTheme(getColorThemeProps(reprProps)) + // } return <div> <div> @@ -68,7 +65,7 @@ export class RepresentationComponent extends React.Component<RepresentationCompo onChange={(k, v) => this.onChange(k as string, v)} /> </div> - { colorTheme !== undefined ? <ColorThemeComponent colorTheme={colorTheme} /> : '' } + {/* { colorTheme !== undefined ? <ColorThemeComponent colorTheme={colorTheme} /> : '' } */} </div>; } } \ No newline at end of file diff --git a/src/apps/canvas/component/structure-view.tsx b/src/apps/canvas/component/structure-view.tsx index 9b8fd7d785b34911588028d951b22b6224668994..3bfd625633ef9a6999b8ef87589486270581b6c1 100644 --- a/src/apps/canvas/component/structure-view.tsx +++ b/src/apps/canvas/component/structure-view.tsx @@ -7,8 +7,8 @@ import * as React from 'react' import { StructureView } from '../structure-view'; import { RepresentationComponent } from './representation'; -import { Representation } from 'mol-repr'; -import { StructureRepresentation } from 'mol-repr/structure/index'; +import { Representation } from 'mol-repr/representation'; +import { StructureRepresentation } from 'mol-repr/structure/representation'; export interface StructureViewComponentProps { structureView: StructureView @@ -37,6 +37,7 @@ export class StructureViewComponent extends React.Component<StructureViewCompone structureView: sv, label: sv.label, + structure: sv.structure, modelId: sv.modelId, modelIds: sv.getModelIds(), assemblyId: sv.assemblyId, @@ -84,7 +85,7 @@ export class StructureViewComponent extends React.Component<StructureViewCompone } render() { - const { structureView, label, modelIds, assemblyIds, symmetryFeatureIds, active, structureRepresentations } = this.state + const { structureView, label, structure, modelIds, assemblyIds, symmetryFeatureIds, active, structureRepresentations } = this.state const modelIdOptions = modelIds.map(m => { return <option key={m.id} value={m.id}>{m.label}</option> @@ -174,6 +175,9 @@ export class StructureViewComponent extends React.Component<StructureViewCompone return <div key={i}> <RepresentationComponent repr={structureRepresentations[k] as Representation<any>} + params={ + structureView.app.structureRepresentationRegistry.get(k)!.params(structureView.app.reprCtx, structure!) + } canvas3d={structureView.canvas3d} app={structureView.app} /> diff --git a/src/apps/canvas/component/volume-view.tsx b/src/apps/canvas/component/volume-view.tsx index 159a0d2176dc108377d34cfa1147038d75bbb852..bf351b4dc38f9782f086df4353f48761bf83c400 100644 --- a/src/apps/canvas/component/volume-view.tsx +++ b/src/apps/canvas/component/volume-view.tsx @@ -6,9 +6,9 @@ import * as React from 'react' import { RepresentationComponent } from './representation'; -import { Representation } from 'mol-repr'; +import { Representation } from 'mol-repr/representation'; import { VolumeView } from '../volume-view'; -import { VolumeRepresentation } from 'mol-repr/volume/index'; +import { VolumeRepresentation } from 'mol-repr/volume/representation'; export interface VolumeViewComponentProps { volumeView: VolumeView @@ -28,6 +28,7 @@ export class VolumeViewComponent extends React.Component<VolumeViewComponentProp return { volumeView: vv, label: vv.label, + volume: vv.volume, active: vv.active, volumeRepresentations: vv.volumeRepresentations } @@ -61,7 +62,7 @@ export class VolumeViewComponent extends React.Component<VolumeViewComponentProp // } render() { - const { volumeView, label, active, volumeRepresentations } = this.state + const { volumeView, label, volume, active, volumeRepresentations } = this.state return <div> <div> @@ -89,6 +90,9 @@ export class VolumeViewComponent extends React.Component<VolumeViewComponentProp return <div key={i}> <RepresentationComponent repr={volumeRepresentations[k] as Representation<any>} + params={ + volumeView.app.volumeRepresentationRegistry.get(k)!.params(volumeView.app.reprCtx, volume!) + } canvas3d={volumeView.viewer} app={volumeView.app} /> diff --git a/src/apps/canvas/structure-view.ts b/src/apps/canvas/structure-view.ts index eeff5581a4cb6d4dcc4e95fe1055642be4122aee..5f80091c05466fc21c26c6140c49d86bcc837ec0 100644 --- a/src/apps/canvas/structure-view.ts +++ b/src/apps/canvas/structure-view.ts @@ -17,15 +17,8 @@ import Canvas3D from 'mol-canvas3d/canvas3d'; // import { addBoundingBox } from 'mol-geo/mesh/builder/bounding-box'; import { BehaviorSubject } from 'rxjs'; import { App } from './app'; -import { StructureRepresentation } from 'mol-repr/structure/index'; -import { ShapeRepresentation, ShapeProps } from 'mol-repr/shape/index'; -import { CartoonRepresentation } from 'mol-repr/structure/representation/cartoon'; -import { MolecularSurfaceRepresentation } from 'mol-repr/structure/representation/molecular-surface'; -import { PointRepresentation } from 'mol-repr/structure/representation/point'; -import { BallAndStickRepresentation } from 'mol-repr/structure/representation/ball-and-stick'; -import { CarbohydrateRepresentation } from 'mol-repr/structure/representation/carbohydrate'; -import { SpacefillRepresentation } from 'mol-repr/structure/representation/spacefill'; -import { DistanceRestraintRepresentation } from 'mol-repr/structure/representation/distance-restraint'; +import { StructureRepresentation } from 'mol-repr/structure/representation'; +import { ShapeRepresentation, ShapeProps } from 'mol-repr/shape/representation'; export interface StructureView { readonly app: App @@ -66,25 +59,17 @@ interface StructureViewProps { export async function StructureView(app: App, canvas3d: Canvas3D, models: ReadonlyArray<Model>, props: StructureViewProps = {}): Promise<StructureView> { const active: { [k: string]: boolean } = { cartoon: true, - point: false, - surface: false, - ballAndStick: false, - carbohydrate: false, - spacefill: false, - distanceRestraint: false, - symmetryAxes: true, + // point: false, + // surface: false, + // ballAndStick: false, + // carbohydrate: false, + // spacefill: false, + // distanceRestraint: false, + // symmetryAxes: true, // polymerSphere: false, } - const structureRepresentations: { [k: string]: StructureRepresentation<any> } = { - cartoon: CartoonRepresentation(), - surface: MolecularSurfaceRepresentation(), - point: PointRepresentation(), - ballAndStick: BallAndStickRepresentation(), - carbohydrate: CarbohydrateRepresentation(), - spacefill: SpacefillRepresentation(), - distanceRestraint: DistanceRestraintRepresentation(), - } + const structureRepresentations: { [k: string]: StructureRepresentation<any> } = {} const symmetryAxes = ShapeRepresentation() const polymerSphere = ShapeRepresentation() @@ -206,14 +191,25 @@ export async function StructureView(app: App, canvas3d: Canvas3D, models: Readon async function createStructureRepr() { if (structure) { console.log('createStructureRepr') - for (const k in structureRepresentations) { + for (const k in active) { if (active[k]) { - await app.runTask(structureRepresentations[k].createOrUpdate({ webgl: canvas3d.webgl }, {}, structure).run( + let repr: StructureRepresentation + if (structureRepresentations[k]) { + repr = structureRepresentations[k] + } else { + repr = app.structureRepresentationRegistry.create('cartoon', app.reprCtx, structure) + structureRepresentations[k] = repr + } + await app.runTask(repr.createOrUpdate(app.reprCtx, {}, {}, structure).run( progress => app.log(progress) ), 'Create/update representation') - canvas3d.add(structureRepresentations[k]) + canvas3d.add(repr) } else { - canvas3d.remove(structureRepresentations[k]) + if (structureRepresentations[k]) { + canvas3d.remove(structureRepresentations[k]) + structureRepresentations[k].destroy() + delete structureRepresentations[k] + } } } @@ -264,7 +260,7 @@ export async function StructureView(app: App, canvas3d: Canvas3D, models: Readon // colorFunction: colorTheme.color, // colorGranularity: colorTheme.granularity, // }).run() - await symmetryAxes.createOrUpdate({ webgl: canvas3d.webgl }, {}, axesShape).run() + await symmetryAxes.createOrUpdate(app.reprCtx, {}, {}, axesShape).run() canvas3d.add(symmetryAxes) } else { canvas3d.remove(symmetryAxes) diff --git a/src/apps/canvas/volume-view.ts b/src/apps/canvas/volume-view.ts index 6c05559ef90422c25527822337f72f7e0e602d02..023f16fec99ffc3be3bdee4b09139dac1f43e65c 100644 --- a/src/apps/canvas/volume-view.ts +++ b/src/apps/canvas/volume-view.ts @@ -8,7 +8,7 @@ import Canvas3D from 'mol-canvas3d/canvas3d'; import { BehaviorSubject } from 'rxjs'; import { App } from './app'; import { VolumeData } from 'mol-model/volume'; -import { VolumeRepresentation } from 'mol-repr/volume/index'; +import { VolumeRepresentation } from 'mol-repr/volume/representation'; import { IsosurfaceRepresentation } from 'mol-repr/volume/isosurface-mesh'; import { DirectVolumeRepresentation } from 'mol-repr/volume/direct-volume'; @@ -54,7 +54,7 @@ export async function VolumeView(app: App, viewer: Canvas3D, volume: VolumeData, async function createVolumeRepr() { for (const k in volumeRepresentations) { if (active[k]) { - await app.runTask(volumeRepresentations[k].createOrUpdate({ webgl: viewer.webgl }, {}, volume).run( + await app.runTask(volumeRepresentations[k].createOrUpdate(app.reprCtx, {}, {}, volume).run( progress => app.log(progress) ), 'Create/update representation') viewer.add(volumeRepresentations[k]) diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index 2f6bd0b460136e3c653cdbf485b70044475b8fbd..576e0d68ce2d079ff4c0f0198c78af661d66bd85 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -16,7 +16,7 @@ import TrackballControls from './controls/trackball' import { Viewport } from './camera/util' import { resizeCanvas } from './util'; import { createContext, getGLContext, WebGLContext } from 'mol-gl/webgl/context'; -import { Representation } from 'mol-repr'; +import { Representation } from 'mol-repr/representation'; import { createRenderTarget } from 'mol-gl/webgl/render-target'; import Scene from 'mol-gl/scene'; import { RenderVariant } from 'mol-gl/webgl/render-item'; diff --git a/src/mol-geo/geometry/color-data.ts b/src/mol-geo/geometry/color-data.ts index d9d798acc569fbbace36806b517015e0690e11fd..fe85ae1bc6e206d2a03a0c57aaf68830d3446894 100644 --- a/src/mol-geo/geometry/color-data.ts +++ b/src/mol-geo/geometry/color-data.ts @@ -6,14 +6,13 @@ import { ValueCell } from 'mol-util'; import { TextureImage, createTextureImage } from 'mol-gl/renderable/util'; -import { Color, ColorMap } from 'mol-util/color'; +import { Color } from 'mol-util/color'; import { Vec2, Vec3 } from 'mol-math/linear-algebra'; import { LocationIterator } from '../util/location-iterator'; import { NullLocation } from 'mol-model/location'; -import { LocationColor, ColorThemeProps, ColorTheme, ColorThemeName, ScaleLegend, TableLegend, ColorScaleName, getColorScaleFromName } from 'mol-theme/color'; +import { LocationColor, ColorTheme } from 'mol-theme/color'; import { RuntimeContext } from 'mol-task'; import { getGranularity } from './geometry'; -import { Structure } from 'mol-model/structure'; export type ColorType = 'uniform' | 'instance' | 'group' | 'groupInstance' @@ -25,37 +24,6 @@ export type ColorData = { dColorType: ValueCell<string>, } -export interface ColorProps { - colorTheme: ColorThemeName - colorList?: Color[] | ColorScaleName - colorMap?: ColorMap<any> - colorDomain?: [number, number] - colorValue?: Color - colorFunction?: LocationColor, - colorGranularity?: ColorType, - colorDescription?: string, - colorLegend?: ScaleLegend | TableLegend - structure?: Structure -} - -export function getColorThemeProps(props: ColorProps): ColorThemeProps { - const p: ColorThemeProps = { - name: props.colorTheme - } - if (props.colorDomain !== undefined) p.domain = props.colorDomain - if (props.colorList !== undefined) { - p.list = typeof props.colorList === 'string' ? getColorScaleFromName(props.colorList) : props.colorList - } - if (props.colorMap !== undefined) p.map = props.colorMap - if (props.colorValue !== undefined) p.value = props.colorValue - if (props.structure !== undefined) p.structure = props.structure - if (props.colorFunction !== undefined) p.color = props.colorFunction - if (props.colorGranularity !== undefined) p.granularity = props.colorGranularity - if (props.colorDescription !== undefined) p.description = props.colorDescription - if (props.colorLegend !== undefined) p.legend = props.colorLegend - return p -} - export function createColors(ctx: RuntimeContext, locationIt: LocationIterator, colorTheme: ColorTheme, colorData?: ColorData): Promise<ColorData> { switch (getGranularity(locationIt, colorTheme.granularity)) { case 'uniform': return createUniformColor(ctx, locationIt, colorTheme.color, colorData) diff --git a/src/mol-geo/geometry/direct-volume/direct-volume.ts b/src/mol-geo/geometry/direct-volume/direct-volume.ts index 1e6575fbf7ea4bab48105808a5e02b754bf1f0c9..50dfc577d7e0cca54bd64994313d39bdc6d0d0af 100644 --- a/src/mol-geo/geometry/direct-volume/direct-volume.ts +++ b/src/mol-geo/geometry/direct-volume/direct-volume.ts @@ -17,9 +17,10 @@ import { LocationIterator } from 'mol-geo/util/location-iterator'; import { TransformData } from '../transform-data'; import { createColors } from '../color-data'; import { createMarkers } from '../marker-data'; -import { Geometry, Theme } from '../geometry'; +import { Geometry } from '../geometry'; import { transformPositionArray } from 'mol-geo/util'; import { calculateBoundingSphere } from 'mol-gl/renderable/util'; +import { Theme } from 'mol-theme/theme'; const VolumeBox = Box() const RenderModeOptions = [['isosurface', 'Isosurface'], ['volume', 'Volume']] as [string, string][] diff --git a/src/mol-geo/geometry/direct-volume/transfer-function.ts b/src/mol-geo/geometry/direct-volume/transfer-function.ts index 1679daa27fe7867c4e128141509e5bdd362f4a41..e93515f9c3e814445f6701078fb4dddcb13a83e2 100644 --- a/src/mol-geo/geometry/direct-volume/transfer-function.ts +++ b/src/mol-geo/geometry/direct-volume/transfer-function.ts @@ -29,7 +29,7 @@ export function createTransferFunctionTexture(controlPoints: ControlPoint[], tex ] const scale = ColorScale.create({ domain: [0, 1], - list: ColorMatplotlib.viridis + listOrName: ColorMatplotlib.viridis }) const n = 256 diff --git a/src/mol-geo/geometry/geometry.ts b/src/mol-geo/geometry/geometry.ts index 2bf275c6a9590a367dcbdf54fcb75e886fa87985..c2c082d3150d260ccf45bfb5f31fa9324f32c174 100644 --- a/src/mol-geo/geometry/geometry.ts +++ b/src/mol-geo/geometry/geometry.ts @@ -9,15 +9,14 @@ import { Points } from './points/points'; import { RenderableState } from 'mol-gl/renderable'; import { ValueCell } from 'mol-util'; import { BaseValues } from 'mol-gl/renderable/schema'; -import { Color } from 'mol-util/color'; -import { ColorThemeOptions, ColorThemeName, ColorScaleOptions, ColorScaleName, ColorTheme } from 'mol-theme/color'; import { LocationIterator } from '../util/location-iterator'; -import { ColorType, getColorThemeProps } from './color-data'; -import { SizeType, getSizeThemeProps } from './size-data'; +import { ColorType } from './color-data'; +import { SizeType } from './size-data'; import { Lines } from './lines/lines'; import { ParamDefinition as PD } from 'mol-util/param-definition' import { DirectVolume } from './direct-volume/direct-volume'; -import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; +import { BuiltInSizeThemeOptions, BuiltInSizeThemeName } from 'mol-theme/size'; +import { BuiltInColorThemeName, BuiltInColorThemeOptions } from 'mol-theme/color'; // @@ -36,18 +35,6 @@ export type VisualQuality = keyof typeof VisualQualityInfo export const VisualQualityNames = Object.keys(VisualQualityInfo) export const VisualQualityOptions = VisualQualityNames.map(n => [n, n] as [VisualQuality, string]) -export interface Theme { - color: ColorTheme - size: SizeTheme -} - -export function createTheme(props: Geometry.Props) { - return { - color: ColorTheme(getColorThemeProps(props)), - size: SizeTheme(getSizeThemeProps(props)) - } -} - // export type GeometryKindType = { @@ -76,15 +63,11 @@ export namespace Geometry { visible: PD.Boolean('Visible', '', true), depthMask: PD.Boolean('Depth Mask', '', true), useFog: PD.Boolean('Use Fog', '', false), - quality: PD.Select<VisualQuality>('Quality', '', 'auto', VisualQualityOptions), - colorTheme: PD.Select<ColorThemeName>('Color Name', '', 'uniform', ColorThemeOptions), - colorList: PD.Select<ColorScaleName>('Color Scale', '', 'default', ColorScaleOptions), - colorValue: PD.Color('Color Value', '', Color(0xCCCCCC)), + quality: PD.Select<VisualQuality>('Quality', '', 'auto', VisualQualityOptions), - sizeTheme: PD.Select<SizeThemeName>('Size Name', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), + colorTheme: PD.Select<BuiltInColorThemeName>('Color Name', '', 'uniform', BuiltInColorThemeOptions), + sizeTheme: PD.Select<BuiltInSizeThemeName>('Size Name', '', 'uniform', BuiltInSizeThemeOptions), } export const DefaultProps = PD.getDefaultValues(Params) export type Props = typeof DefaultProps diff --git a/src/mol-geo/geometry/lines/lines.ts b/src/mol-geo/geometry/lines/lines.ts index 54954156927bbeeed26faf7d6b57115a64ad1256..4c5a48a7313b0a431ba858066795b32a77a2d1e5 100644 --- a/src/mol-geo/geometry/lines/lines.ts +++ b/src/mol-geo/geometry/lines/lines.ts @@ -7,7 +7,7 @@ import { ValueCell } from 'mol-util' import { Mat4 } from 'mol-math/linear-algebra' import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util'; -import { Geometry, Theme } from '../geometry'; +import { Geometry } from '../geometry'; import { RuntimeContext } from 'mol-task'; import { createColors } from '../color-data'; import { createMarkers } from '../marker-data'; @@ -20,6 +20,7 @@ import { LinesBuilder } from './lines-builder'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { calculateBoundingSphere } from 'mol-gl/renderable/util'; import { Sphere3D } from 'mol-math/geometry'; +import { Theme } from 'mol-theme/theme'; /** Wide line */ export interface Lines { diff --git a/src/mol-geo/geometry/mesh/mesh.ts b/src/mol-geo/geometry/mesh/mesh.ts index 9d4ca0deba32cafc054e75dce3b86452c416eba7..0c1a8f5cf5556010e58731ced5275e18481845ed 100644 --- a/src/mol-geo/geometry/mesh/mesh.ts +++ b/src/mol-geo/geometry/mesh/mesh.ts @@ -9,8 +9,7 @@ import { ValueCell } from 'mol-util' import { Vec3, Mat4 } from 'mol-math/linear-algebra' import { Sphere3D } from 'mol-math/geometry' import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util'; -import { MeshValues } from 'mol-gl/renderable'; -import { Geometry, Theme } from '../geometry'; +import { Geometry } from '../geometry'; import { createMarkers } from '../marker-data'; import { TransformData } from '../transform-data'; import { LocationIterator } from '../../util/location-iterator'; @@ -18,6 +17,8 @@ import { createColors } from '../color-data'; import { ChunkedArray } from 'mol-data/util'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { calculateBoundingSphere } from 'mol-gl/renderable/util'; +import { Theme } from 'mol-theme/theme'; +import { MeshValues } from 'mol-gl/renderable/mesh'; export interface Mesh { readonly kind: 'mesh', diff --git a/src/mol-geo/geometry/points/points.ts b/src/mol-geo/geometry/points/points.ts index 84a191bf7559f158dc926384f9d44200c4902270..616e7e057ed2e98404bb6185d41e127ba2fc08c9 100644 --- a/src/mol-geo/geometry/points/points.ts +++ b/src/mol-geo/geometry/points/points.ts @@ -7,8 +7,7 @@ import { ValueCell } from 'mol-util' import { Mat4 } from 'mol-math/linear-algebra' import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util'; -import { Geometry, Theme } from '../geometry'; -import { PointsValues } from 'mol-gl/renderable'; +import { Geometry } from '../geometry'; import { RuntimeContext } from 'mol-task'; import { createColors } from '../color-data'; import { createMarkers } from '../marker-data'; @@ -18,6 +17,8 @@ import { LocationIterator } from '../../util/location-iterator'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { calculateBoundingSphere } from 'mol-gl/renderable/util'; import { Sphere3D } from 'mol-math/geometry'; +import { Theme } from 'mol-theme/theme'; +import { PointsValues } from 'mol-gl/renderable/points'; /** Point cloud */ export interface Points { diff --git a/src/mol-geo/geometry/size-data.ts b/src/mol-geo/geometry/size-data.ts index 06cdcef0c6d48ef6d47a333bf9fc58edb3eb14c1..6b791ed0f5839d00c4c10ccdcaa8f7aff90b6840 100644 --- a/src/mol-geo/geometry/size-data.ts +++ b/src/mol-geo/geometry/size-data.ts @@ -10,9 +10,8 @@ import { TextureImage, createTextureImage } from 'mol-gl/renderable/util'; import { LocationIterator } from '../util/location-iterator'; import { Location, NullLocation } from 'mol-model/location'; import { RuntimeContext } from 'mol-task'; -import { SizeThemeProps, SizeTheme, SizeThemeName } from 'mol-theme/size'; +import { SizeTheme } from 'mol-theme/size'; import { getGranularity } from './geometry'; -import { Structure } from 'mol-model/structure'; export type SizeType = 'uniform' | 'instance' | 'group' | 'groupInstance' @@ -24,22 +23,6 @@ export type SizeData = { dSizeType: ValueCell<string>, } -export interface SizeProps { - sizeTheme: SizeThemeName - sizeValue?: number - sizeFactor?: number - structure?: Structure -} - -export function getSizeThemeProps(props: SizeProps): SizeThemeProps { - return { - name: props.sizeTheme, - value: props.sizeValue, - factor: props.sizeFactor, - structure: props.structure, - } -} - export async function createSizes(ctx: RuntimeContext, locationIt: LocationIterator, sizeTheme: SizeTheme, sizeData?: SizeData): Promise<SizeData> { switch (getGranularity(locationIt, sizeTheme.granularity)) { case 'uniform': return createUniformSize(ctx, locationIt, sizeTheme.size, sizeData) diff --git a/src/mol-gl/render-object.ts b/src/mol-gl/render-object.ts index 84e892862ffb3bb336c6ed7b716a124cb106a0d3..f4761dea481de4ed1278c44b68947e64d6eb31e1 100644 --- a/src/mol-gl/render-object.ts +++ b/src/mol-gl/render-object.ts @@ -4,12 +4,15 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { PointsRenderable, MeshRenderable, RenderableState, MeshValues, PointsValues, LinesValues, LinesRenderable, Renderable } from './renderable' +import { RenderableState, Renderable } from './renderable' import { RenderableValues } from './renderable/schema'; import { idFactory } from 'mol-util/id-factory'; import { WebGLContext } from './webgl/context'; import { GaussianDensityValues, GaussianDensityRenderable } from './renderable/gaussian-density'; import { DirectVolumeValues, DirectVolumeRenderable } from './renderable/direct-volume'; +import { MeshValues, MeshRenderable } from './renderable/mesh'; +import { PointsValues, PointsRenderable } from './renderable/points'; +import { LinesValues, LinesRenderable } from './renderable/lines'; const getNextId = idFactory(0, 0x7FFFFFFF) diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts index 8512933e0d78e1beea97d2ba39da357f7bdf8322..370437898cfee60a0df4e37d155640412c21a6fb 100644 --- a/src/mol-gl/renderable.ts +++ b/src/mol-gl/renderable.ts @@ -46,8 +46,4 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem: update: () => renderItem.update(), dispose: () => renderItem.destroy() } -} - -export { MeshRenderable, MeshSchema, MeshValues } from './renderable/mesh' -export { PointsRenderable, PointsSchema, PointsValues } from './renderable/points' -export { LinesRenderable, LinesSchema, LinesValues } from './renderable/lines' \ No newline at end of file +} \ No newline at end of file diff --git a/src/mol-model/structure/structure/unit/gaussian-density.ts b/src/mol-model/structure/structure/unit/gaussian-density.ts index 9e63a7ee5e2d3600260e94dd18c7388438aa7725..0acfa52fdea9448162cfda3b52fd94aeb2367424 100644 --- a/src/mol-model/structure/structure/unit/gaussian-density.ts +++ b/src/mol-model/structure/structure/unit/gaussian-density.ts @@ -5,7 +5,6 @@ */ import { Unit, StructureElement, ElementIndex } from 'mol-model/structure'; -import { SizeTheme } from 'mol-theme/size'; import { GaussianDensity } from 'mol-math/geometry/gaussian-density'; import { Task, RuntimeContext } from 'mol-task'; import { DensityData } from 'mol-math/geometry'; @@ -13,6 +12,7 @@ import { ParamDefinition as PD } from 'mol-util/param-definition'; import { GaussianDensityTexture } from 'mol-math/geometry/gaussian-density/gpu'; import { Texture } from 'mol-gl/webgl/texture'; import { WebGLContext } from 'mol-gl/webgl/context'; +import { PhysicalSizeTheme } from 'mol-theme/size/physical'; export const GaussianDensityParams = { resolution: PD.Numeric('Resolution', '', 1, 0.1, 10, 0.1), @@ -43,7 +43,7 @@ function getConformationAndRadius(unit: Unit) { } const l = StructureElement.create(unit) - const sizeTheme = SizeTheme({ name: 'physical' }) + const sizeTheme = PhysicalSizeTheme({}, {}) const radius = (index: number) => { l.element = index as ElementIndex return sizeTheme.size(l) diff --git a/src/mol-plugin/state/objects.ts b/src/mol-plugin/state/objects.ts index cb2cf337c0014d2a58f957595bce61982c4b9b3b..93b8aa819498e9030408fb4a46e6a6b87fb24515 100644 --- a/src/mol-plugin/state/objects.ts +++ b/src/mol-plugin/state/objects.ts @@ -7,7 +7,7 @@ import { PluginStateObject } from './base'; import { CifFile } from 'mol-io/reader/cif'; import { Model as _Model, Structure as _Structure } from 'mol-model/structure' -import { StructureRepresentation } from 'mol-repr/structure/index'; +import { StructureRepresentation } from 'mol-repr/structure/representation'; const _create = PluginStateObject.Create diff --git a/src/mol-plugin/state/transforms/visuals.ts b/src/mol-plugin/state/transforms/visuals.ts index 3dbb0a621f161399802b8184f55767f729aa3dc6..dc7a49f265798d5d11476f06cc2591312e153ae2 100644 --- a/src/mol-plugin/state/transforms/visuals.ts +++ b/src/mol-plugin/state/transforms/visuals.ts @@ -8,9 +8,16 @@ import { Transformer } from 'mol-state'; import { Task } from 'mol-task'; import { PluginStateTransform } from '../base'; import { PluginStateObjects as SO } from '../objects'; -//import { CartoonRepresentation, DefaultCartoonProps } from 'mol-repr/structure/representation/cartoon'; -import { BallAndStickRepresentation, DefaultBallAndStickProps } from 'mol-repr/structure/representation/ball-and-stick'; +// import { CartoonRepresentation, DefaultCartoonProps } from 'mol-repr/structure/representation/cartoon'; +// import { BallAndStickRepresentation } from 'mol-repr/structure/representation/ball-and-stick'; import { PluginContext } from 'mol-plugin/context'; +import { ColorTheme } from 'mol-theme/color'; +import { SizeTheme } from 'mol-theme/size'; +import { RepresentationRegistry } from 'mol-repr/representation'; + +const colorThemeRegistry = new ColorTheme.Registry() +const sizeThemeRegistry = new SizeTheme.Registry() +const representationRegistry = new RepresentationRegistry() export { CreateStructureRepresentation } namespace CreateStructureRepresentation { export interface Params { } } @@ -21,14 +28,15 @@ const CreateStructureRepresentation = PluginStateTransform.Create<SO.Structure, to: [SO.StructureRepresentation3D], apply({ a, params }, plugin: PluginContext) { return Task.create('Structure Representation', async ctx => { - const repr = BallAndStickRepresentation(); // CartoonRepresentation(); - await repr.createOrUpdate({ webgl: plugin.canvas3d.webgl }, DefaultBallAndStickProps, a.data).runInContext(ctx); + const repr = representationRegistry.create('cartoon', { colorThemeRegistry, sizeThemeRegistry }, a.data) + // const repr = BallAndStickRepresentation(); // CartoonRepresentation(); + await repr.createOrUpdate({ webgl: plugin.canvas3d.webgl, colorThemeRegistry, sizeThemeRegistry }, {}, {}, a.data).runInContext(ctx); return new SO.StructureRepresentation3D({ label: 'Visual Repr.' }, repr); }); }, update({ a, b }, plugin: PluginContext) { return Task.create('Structure Representation', async ctx => { - await b.data.createOrUpdate({ webgl: plugin.canvas3d.webgl }, b.data.props, a.data).runInContext(ctx); + await b.data.createOrUpdate({ webgl: plugin.canvas3d.webgl, colorThemeRegistry, sizeThemeRegistry }, b.data.props, {}, a.data).runInContext(ctx); return Transformer.UpdateResult.Updated; }); } diff --git a/src/mol-repr/index.ts b/src/mol-repr/representation.ts similarity index 58% rename from src/mol-repr/index.ts rename to src/mol-repr/representation.ts index 2ebfe22338168d79a89269562d1033fd98045b11..a0868ba3cc0532cebc2297f733dd97af5bdd0e23 100644 --- a/src/mol-repr/index.ts +++ b/src/mol-repr/representation.ts @@ -12,61 +12,95 @@ import { MarkerAction } from '../mol-geo/geometry/marker-data'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { WebGLContext } from 'mol-gl/webgl/context'; import { getQualityProps } from './util'; -import { Theme } from 'mol-geo/geometry/geometry'; -// import { ColorTheme } from 'mol-theme/color'; +import { ColorTheme } from 'mol-theme/color'; +import { SizeTheme } from 'mol-theme/size'; +import { ThemeProps, Theme, ThemeRegistryContext } from 'mol-theme/theme'; // export interface RepresentationProps { // visuals?: string[] // } export type RepresentationProps = { [k: string]: any } +// + +export interface RepresentationProvider<D, P extends PD.Params> { + readonly factory: (defaultProps: PD.DefaultValues<P>) => Representation<D, PD.DefaultValues<P>> + readonly params: (ctx: ThemeRegistryContext, data: D) => P +} + +export class RepresentationRegistry<D> { + private _list: { name: string, provider: RepresentationProvider<D, any> }[] = [] + private _map = new Map<string, RepresentationProvider<D, any>>() + + constructor() {}; + + add<P extends PD.Params>(name: string, factory: RepresentationProvider<D, P>['factory'], params: RepresentationProvider<D, P>['params']) { + const provider = { factory, params } as RepresentationProvider<D, P> + this._list.push({ name, provider }) + this._map.set(name, provider) + } + + get(id: string) { + return this._map.get(id) + } + + create(id: string, ctx: ThemeRegistryContext, data: D, props = {}): Representation<D, any> { + const provider = this.get(id) + return provider ? provider.factory({ ...PD.getDefaultValues(provider.params(ctx, data)), ...props }) : Representation.Empty + } + + get list() { + return this._list + } +} + +// + export interface RepresentationContext { webgl?: WebGLContext + colorThemeRegistry: ColorTheme.Registry + sizeThemeRegistry: SizeTheme.Registry } -export interface Representation<D, P extends RepresentationProps = {}> { +export { Representation } +interface Representation<D, P extends RepresentationProps = {}> { readonly label: string - readonly params: PD.Params readonly renderObjects: ReadonlyArray<RenderObject> readonly props: Readonly<P> - createOrUpdate: (ctx: RepresentationContext, props?: Partial<P>, data?: D) => Task<void> + createOrUpdate: (ctx: RepresentationContext, props?: Partial<P>, themeProps?: ThemeProps, data?: D) => Task<void> getLoci: (pickingId: PickingId) => Loci mark: (loci: Loci, action: MarkerAction) => boolean destroy: () => void } - -export namespace Representation { +namespace Representation { export type Any = Representation<any> - export const Empty: Representation<undefined> = { - label: '', params: {}, renderObjects: [], props: {}, + export const Empty: Representation<any> = { + label: '', renderObjects: [], props: {}, createOrUpdate: () => Task.constant('', undefined), getLoci: () => EmptyLoci, mark: () => false, destroy: () => {} } - export function createMulti<D, P extends RepresentationProps = {}>(label: string, params: PD.Params, defaultProps: P, reprList: Representation<D, P>[]): Representation<D, P> { - let currentProps: P + export type Def<P extends RepresentationProps = {}> = { [k: string]: (defaultProps: P) => Representation<any, P> } + + export function createMulti<D, P extends RepresentationProps = {}>(label: string, defaultProps: P, reprDefs: Def<P>): Representation<D, P> { + let currentProps: P = Object.assign({}, defaultProps) let currentData: D - const visualsOptions: [string, string][] = [] - for (let i = 0, il = reprList.length; i < il; ++i) { - visualsOptions.push([ i.toString(), reprList[i].label ]) - } - params['visuals'] = PD.MultiSelect<string>('Visuals', '', ['surface'], visualsOptions) - - if (!defaultProps.visuals) { - defaultProps.visuals = reprList.map((r, i) => i.toString()) - } + const reprMap: { [k: number]: string } = {} + const reprList: Representation<D, P>[] = Object.keys(reprDefs).map((name, i) => { + reprMap[i] = name + return reprDefs[name](defaultProps) + }) return { label, - params, get renderObjects() { const { visuals } = currentProps const renderObjects: RenderObject[] = [] for (let i = 0, il = reprList.length; i < il; ++i) { - if (!visuals || visuals.includes(i.toString())) { + if (!visuals || visuals.includes(reprMap[i])) { renderObjects.push(...reprList[i].renderObjects) } } @@ -77,16 +111,16 @@ export namespace Representation { reprList.forEach(r => Object.assign(props, r.props)) return props as P }, - createOrUpdate: (ctx: RepresentationContext, props: Partial<P> = {}, data?: D) => { + createOrUpdate: (ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, data?: D) => { if (data) currentData = data - const qualityProps = getQualityProps(Object.assign({}, currentProps, props), data) - currentProps = Object.assign({}, defaultProps, currentProps, props, qualityProps) + const qualityProps = getQualityProps(Object.assign({}, currentProps, props), currentData) + Object.assign(currentProps, props, qualityProps) const { visuals } = currentProps return Task.create(`Creating '${label}' representation`, async runtime => { for (let i = 0, il = reprList.length; i < il; ++i) { - if (!visuals || visuals.includes(i.toString())) { - await reprList[i].createOrUpdate(ctx, currentProps, currentData).runInContext(runtime) + if (!visuals || visuals.includes(reprMap[i])) { + await reprList[i].createOrUpdate(ctx, currentProps, themeProps, currentData).runInContext(runtime) } } }) @@ -116,7 +150,8 @@ export namespace Representation { // -export interface VisualContext extends RepresentationContext { +export interface VisualContext { + webgl?: WebGLContext runtime: RuntimeContext, } diff --git a/src/mol-repr/shape/index.ts b/src/mol-repr/shape/representation.ts similarity index 91% rename from src/mol-repr/shape/index.ts rename to src/mol-repr/shape/representation.ts index 632458983dd63be0c085552b95fa36daae7cfeaf..718f68ce30e76ccee8487d969e53f7b234de776e 100644 --- a/src/mol-repr/shape/index.ts +++ b/src/mol-repr/shape/representation.ts @@ -6,25 +6,26 @@ import { Task } from 'mol-task' import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'; -import { RepresentationProps, Representation, RepresentationContext } from '..'; +import { RepresentationProps, Representation, RepresentationContext } from '../representation'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; import { ValueCell } from 'mol-util'; -import { ColorThemeName, ColorThemeOptions } from 'mol-theme/color'; import { Shape } from 'mol-model/shape'; import { OrderedSet, Interval } from 'mol-data/int'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; -import { createRenderableState, createTheme } from 'mol-geo/geometry/geometry'; +import { createRenderableState } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data'; import { LocationIterator } from 'mol-geo/util/location-iterator'; +import { ThemeProps, createTheme } from 'mol-theme/theme'; export interface ShapeRepresentation<P extends RepresentationProps = {}> extends Representation<Shape, P> { } export const ShapeParams = { ...Mesh.Params, - colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'shape-group', ColorThemeOptions) + // TODO + // colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'shape-group', ColorThemeOptions) } export const DefaultShapeProps = PD.getDefaultValues(ShapeParams) export type ShapeProps = typeof DefaultShapeProps @@ -38,7 +39,7 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation let _shape: Shape let currentProps: P - function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, shape?: Shape) { + function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, shape?: Shape) { currentProps = Object.assign({}, DefaultShapeProps, currentProps, props) if (shape) _shape = shape @@ -49,7 +50,7 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation const mesh = _shape.mesh const locationIt = ShapeGroupIterator.fromShape(_shape) - const theme = createTheme(currentProps) + const theme = createTheme(ctx, currentProps, themeProps, {}) const transform = createIdentityTransform() const values = await Mesh.createValues(runtime, mesh, transform, locationIt, theme, currentProps) @@ -62,7 +63,6 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation return { label: 'Shape mesh', - params: ShapeParams, get renderObjects () { return renderObjects }, get props () { return currentProps }, createOrUpdate, diff --git a/src/mol-repr/structure/complex-representation.ts b/src/mol-repr/structure/complex-representation.ts index 58529f5dd1b6c43a45a5ace7b7f01a0544052ea2..607a1047b87f479f60330c241132239f88548098 100644 --- a/src/mol-repr/structure/complex-representation.ts +++ b/src/mol-repr/structure/complex-representation.ts @@ -8,23 +8,24 @@ import { Structure } from 'mol-model/structure'; import { Task } from 'mol-task' import { Loci, EmptyLoci } from 'mol-model/loci'; -import { StructureProps, StructureRepresentation, StructureParams } from './index'; +import { StructureProps, StructureRepresentation } from './representation'; import { ComplexVisual } from './complex-visual'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; -import { RepresentationContext } from 'mol-repr'; -import { createTheme, Theme } from 'mol-geo/geometry/geometry'; +import { RepresentationContext } from 'mol-repr/representation'; +import { Theme, ThemeProps, createTheme } from 'mol-theme/theme'; -export function ComplexRepresentation<P extends StructureProps>(label: string, visualCtor: () => ComplexVisual<P>): StructureRepresentation<P> { +export function ComplexRepresentation<P extends StructureProps>(label: string, defaultProps: P, visualCtor: () => ComplexVisual<P>): StructureRepresentation<P> { let visual: ComplexVisual<P> | undefined + let _structure: Structure - let _props: P + let _props: P = Object.assign({}, defaultProps) let _theme: Theme - function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, structure?: Structure) { + function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, structure?: Structure) { if (structure) _structure = structure - _props = Object.assign({}, _props, props, { structure: _structure }) - _theme = createTheme(_props) + _props = Object.assign({}, _props, props) + _theme = createTheme(ctx, { structure: _structure }, props, themeProps, _theme) return Task.create('Creating or updating ComplexRepresentation', async runtime => { if (!visual) visual = visualCtor() @@ -46,7 +47,6 @@ export function ComplexRepresentation<P extends StructureProps>(label: string, v return { label, - params: StructureParams, // TODO get renderObjects() { return visual && visual.renderObject ? [ visual.renderObject ] : [] }, diff --git a/src/mol-repr/structure/complex-visual.ts b/src/mol-repr/structure/complex-visual.ts index 4440129f999ebde9726e73d8ada58117e3db3743..75363b93f38601606a1af658ce5def7b62845969 100644 --- a/src/mol-repr/structure/complex-visual.ts +++ b/src/mol-repr/structure/complex-visual.ts @@ -5,23 +5,26 @@ */ import { Structure } from 'mol-model/structure'; -import { Visual, VisualContext } from '..'; +import { Visual, VisualContext } from '../representation'; import { MeshRenderObject, LinesRenderObject, PointsRenderObject, DirectVolumeRenderObject } from 'mol-gl/render-object'; import { createComplexMeshRenderObject, UnitKind, UnitKindOptions } from './visual/util/common'; -import { StructureProps, StructureMeshParams, StructureParams } from './index'; +import { StructureProps, StructureMeshParams, StructureParams } from './representation'; import { deepEqual, ValueCell } from 'mol-util'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; import { Interval } from 'mol-data/int'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { RenderableValues } from 'mol-gl/renderable/schema'; import { createSizes } from 'mol-geo/geometry/size-data'; -import { Geometry, updateRenderableState, Theme } from 'mol-geo/geometry/geometry'; +import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { createColors } from 'mol-geo/geometry/color-data'; import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; -import { VisualUpdateState, colorChanged, sizeChanged } from 'mol-repr/util'; +import { VisualUpdateState } from 'mol-repr/util'; +import { Theme } from 'mol-theme/theme'; +import { ColorTheme } from 'mol-theme/color'; +import { SizeTheme } from 'mol-theme/size'; export interface ComplexVisual<P extends StructureProps> extends Visual<Structure, P> { } @@ -40,7 +43,7 @@ interface ComplexVisualBuilder<P extends ComplexProps, G extends Geometry> { createLocationIterator(structure: Structure): LocationIterator getLoci(pickingId: PickingId, structure: Structure, id: number): Loci mark(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean): boolean, - setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void + setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme): void } interface ComplexVisualGeometryBuilder<P extends ComplexProps, G extends Geometry> extends ComplexVisualBuilder<P, G> { @@ -56,6 +59,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual let renderObject: ComplexRenderObject | undefined let currentProps: P + let currentTheme: Theme let geometry: Geometry let currentStructure: Structure let locationIt: LocationIterator @@ -63,6 +67,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual async function create(ctx: VisualContext, structure: Structure, theme: Theme, props: Partial<P> = {}) { currentProps = Object.assign({}, defaultProps, props) + currentTheme = theme currentStructure = structure conformationHash = Structure.conformationHash(currentStructure) @@ -79,7 +84,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual locationIt.reset() VisualUpdateState.reset(updateState) - setUpdateState(updateState, newProps, currentProps) + setUpdateState(updateState, newProps, currentProps, theme, currentTheme) const newConformationHash = Structure.conformationHash(currentStructure) if (newConformationHash !== conformationHash) { @@ -87,7 +92,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual updateState.createGeometry = true } - if (colorChanged(currentProps, newProps)) updateState.updateColor = true + if (ColorTheme.areEqual(theme.color, currentTheme.color)) updateState.updateColor = true if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true // @@ -113,6 +118,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual updateRenderableState(renderObject.state, newProps) currentProps = newProps + currentTheme = theme return true } @@ -178,9 +184,9 @@ export interface ComplexMeshVisualBuilder<P extends ComplexMeshProps> extends Co export function ComplexMeshVisual<P extends ComplexMeshProps>(builder: ComplexMeshVisualBuilder<P>): ComplexVisual<P> { return ComplexVisual({ ...builder, - setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => { - builder.setUpdateState(state, newProps, currentProps) - if (sizeChanged(currentProps, newProps)) state.createGeometry = true + setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => { + builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme) + if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true }, createEmptyGeometry: Mesh.createEmpty, createRenderObject: createComplexMeshRenderObject, diff --git a/src/mol-repr/structure/registry.ts b/src/mol-repr/structure/registry.ts new file mode 100644 index 0000000000000000000000000000000000000000..90822d785f74c2f767e613df604f01718231a643 --- /dev/null +++ b/src/mol-repr/structure/registry.ts @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Structure } from 'mol-model/structure'; +import { RepresentationProvider, RepresentationRegistry } from '../representation'; +import { CartoonRepresentationProvider } from './representation/cartoon'; + +export class StructureRepresentationRegistry extends RepresentationRegistry<Structure> { + constructor() { + super() + Object.keys(BuiltInStructureRepresentations).forEach(name => { + const p = (BuiltInStructureRepresentations as { [k: string]: RepresentationProvider<Structure, any> })[name] + this.add(name, p.factory, p.params) + }) + } +} + +export const BuiltInStructureRepresentations = { + 'cartoon': CartoonRepresentationProvider, +} +export type BuiltInStructureRepresentationsName = keyof typeof BuiltInStructureRepresentations +export const BuiltInStructureRepresentationsNames = Object.keys(BuiltInStructureRepresentations) +export const BuiltInStructureRepresentationsOptions = BuiltInStructureRepresentationsNames.map(n => [n, n] as [BuiltInStructureRepresentationsName, string]) \ No newline at end of file diff --git a/src/mol-repr/structure/index.ts b/src/mol-repr/structure/representation.ts similarity index 81% rename from src/mol-repr/structure/index.ts rename to src/mol-repr/structure/representation.ts index a0fb183ab0af993ff82b53c30450c6c08635bc00..80a6116037aac73908e19e7a39ab7692a2266b6f 100644 --- a/src/mol-repr/structure/index.ts +++ b/src/mol-repr/structure/representation.ts @@ -6,9 +6,7 @@ */ import { Structure } from 'mol-model/structure'; -import { ColorThemeName, ColorThemeOptions } from 'mol-theme/color'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; -import { Representation, RepresentationProps } from '..'; +import { Representation, RepresentationProps, RepresentationProvider } from '../representation'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Geometry } from 'mol-geo/geometry/geometry'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; @@ -17,12 +15,13 @@ import { Lines } from 'mol-geo/geometry/lines/lines'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; export interface StructureRepresentation<P extends RepresentationProps = {}> extends Representation<Structure, P> { } -// export interface StructureVisual<P extends RepresentationProps = {}> extends Visual<Structure, P> { } + +export type StructureRepresentationProvider<P extends PD.Params> = RepresentationProvider<Structure, P> + +// export const StructureParams = { ...Geometry.Params, - colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'polymer-index', ColorThemeOptions), - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), } export const DefaultStructureProps = PD.getDefaultValues(StructureParams) export type StructureProps = typeof DefaultStructureProps diff --git a/src/mol-repr/structure/representation/backbone.ts b/src/mol-repr/structure/representation/backbone.ts index 33731218d0a9387e5bc7aaa6594ca5807f93f3df..0105026f30b8f29a1e5212a38805aa6d50c6b1f8 100644 --- a/src/mol-repr/structure/representation/backbone.ts +++ b/src/mol-repr/structure/representation/backbone.ts @@ -1,25 +1,29 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ +// /** +// * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author Alexander Rose <alexander.rose@weirdbyte.de> +// */ -import { PolymerBackboneVisual, PolymerBackboneParams } from '../visual/polymer-backbone-cylinder'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { UnitsRepresentation } from '../units-representation'; -import { StructureRepresentation } from '../index'; -import { Representation } from 'mol-repr'; +// import { PolymerBackboneVisual, PolymerBackboneParams } from '../visual/polymer-backbone-cylinder'; +// import { ParamDefinition as PD } from 'mol-util/param-definition'; +// import { UnitsRepresentation } from '../units-representation'; +// import { StructureRepresentation } from '../representation'; +// import { Representation } from 'mol-repr/representation'; +// import { ThemeRegistryContext } from 'mol-theme/theme'; +// import { Structure } from 'mol-model/structure'; -export const BackboneParams = { - ...PolymerBackboneParams -} -export const DefaultBackboneProps = PD.getDefaultValues(BackboneParams) -export type BackboneProps = typeof DefaultBackboneProps +// export const BackboneParams = { +// ...PolymerBackboneParams, +// } +// export function getBackboneParams(ctx: ThemeRegistryContext, structure: Structure) { +// return BackboneParams // TODO return copy +// } +// export type BackboneProps = PD.DefaultValues<typeof BackboneParams> -export type BackboneRepresentation = StructureRepresentation<BackboneProps> +// export type BackboneRepresentation = StructureRepresentation<BackboneProps> -export function BackboneRepresentation(): BackboneRepresentation { - return Representation.createMulti('Backbone', BackboneParams, DefaultBackboneProps, [ - UnitsRepresentation('Polymer backbone cylinder', PolymerBackboneVisual) - ] as StructureRepresentation<BackboneProps>[]) -} \ No newline at end of file +// export function BackboneRepresentation(defaultProps: BackboneProps): BackboneRepresentation { +// return Representation.createMulti('Backbone', defaultProps, [ +// UnitsRepresentation('Polymer backbone cylinder', defaultProps, PolymerBackboneVisual) +// ]) +// } \ No newline at end of file diff --git a/src/mol-repr/structure/representation/ball-and-stick.ts b/src/mol-repr/structure/representation/ball-and-stick.ts index 7f94d0bf8be200c636df1461daa11fcacd889986..e8efe097138b194a47823d1b92fefa5a1e095fe7 100644 --- a/src/mol-repr/structure/representation/ball-and-stick.ts +++ b/src/mol-repr/structure/representation/ball-and-stick.ts @@ -1,38 +1,38 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ +// /** +// * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author Alexander Rose <alexander.rose@weirdbyte.de> +// */ -import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere'; -import { IntraUnitLinkVisual, IntraUnitLinkParams } from '../visual/intra-unit-link-cylinder'; -import { InterUnitLinkVisual, InterUnitLinkParams } from '../visual/inter-unit-link-cylinder'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { UnitKind, UnitKindOptions } from '../visual/util/common'; -import { UnitsRepresentation } from '../units-representation'; -import { ComplexRepresentation } from '../complex-representation'; -import { StructureRepresentation } from '../index'; -import { Representation } from 'mol-repr'; +// import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere'; +// import { IntraUnitLinkVisual, IntraUnitLinkParams } from '../visual/intra-unit-link-cylinder'; +// import { InterUnitLinkVisual, InterUnitLinkParams } from '../visual/inter-unit-link-cylinder'; +// import { ParamDefinition as PD } from 'mol-util/param-definition'; +// import { UnitsRepresentation } from '../units-representation'; +// import { ComplexRepresentation } from '../complex-representation'; +// import { StructureRepresentation } from '../representation'; +// import { Representation } from 'mol-repr/representation'; +// import { ThemeRegistryContext } from 'mol-theme/theme'; +// import { Structure } from 'mol-model/structure'; -export const BallAndStickParams = { - ...ElementSphereParams, - ...IntraUnitLinkParams, - ...InterUnitLinkParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), - unitKinds: PD.MultiSelect<UnitKind>('Unit Kind', '', ['atomic'], UnitKindOptions), -} -export const DefaultBallAndStickProps = PD.getDefaultValues(BallAndStickParams) -export type BallAndStickProps = typeof DefaultBallAndStickProps +// export const BallAndStickParams = { +// ...ElementSphereParams, +// ...IntraUnitLinkParams, +// ...InterUnitLinkParams, +// // TODO +// // unitKinds: PD.MultiSelect<UnitKind>('Unit Kind', '', ['atomic'], UnitKindOptions), +// } +// export function getBallAndStickParams(ctx: ThemeRegistryContext, structure: Structure) { +// return BallAndStickParams // TODO return copy +// } +// export type BallAndStickProps = PD.DefaultValues<typeof BallAndStickParams> -export type BallAndStickRepresentation = StructureRepresentation<BallAndStickProps> +// export type BallAndStickRepresentation = StructureRepresentation<BallAndStickProps> -export function BallAndStickRepresentation(): BallAndStickRepresentation { - return Representation.createMulti('Ball & Stick', BallAndStickParams, DefaultBallAndStickProps, [ - UnitsRepresentation('Element sphere mesh', ElementSphereVisual), - UnitsRepresentation('Intra-unit link cylinder', IntraUnitLinkVisual), - ComplexRepresentation('Inter-unit link cylinder', InterUnitLinkVisual) - ] as unknown as StructureRepresentation<BallAndStickProps>[]) // TODO avoid cast to unknown -} \ No newline at end of file +// export function BallAndStickRepresentation(defaultProps: BallAndStickProps): BallAndStickRepresentation { +// return Representation.createMulti('Ball & Stick', defaultProps, [ +// UnitsRepresentation('Element sphere mesh', defaultProps, ElementSphereVisual), +// UnitsRepresentation('Intra-unit link cylinder', defaultProps, IntraUnitLinkVisual), +// ComplexRepresentation('Inter-unit link cylinder', defaultProps, InterUnitLinkVisual) +// ]) +// } \ No newline at end of file diff --git a/src/mol-repr/structure/representation/carbohydrate.ts b/src/mol-repr/structure/representation/carbohydrate.ts index 3a0c79e9ad004992b88dcfc125ee2343c186fdbd..6493be0aeaaf44ebb3372d507ee41f7e074efbb7 100644 --- a/src/mol-repr/structure/representation/carbohydrate.ts +++ b/src/mol-repr/structure/representation/carbohydrate.ts @@ -1,32 +1,32 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ +// /** +// * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author Alexander Rose <alexander.rose@weirdbyte.de> +// */ -import { CarbohydrateSymbolVisual, CarbohydrateSymbolParams } from '../visual/carbohydrate-symbol-mesh'; -import { CarbohydrateLinkVisual, CarbohydrateLinkParams } from '../visual/carbohydrate-link-cylinder'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { ComplexRepresentation } from '../complex-representation'; -import { StructureRepresentation } from '../index'; -import { Representation } from 'mol-repr'; +// import { CarbohydrateSymbolVisual, CarbohydrateSymbolParams } from '../visual/carbohydrate-symbol-mesh'; +// import { CarbohydrateLinkVisual, CarbohydrateLinkParams } from '../visual/carbohydrate-link-cylinder'; +// import { ParamDefinition as PD } from 'mol-util/param-definition'; +// import { ComplexRepresentation } from '../complex-representation'; +// import { StructureRepresentation } from '../representation'; +// import { Representation } from 'mol-repr/representation'; +// import { ThemeRegistryContext } from 'mol-theme/theme'; +// import { Structure } from 'mol-model/structure'; -export const CarbohydrateParams = { - ...CarbohydrateSymbolParams, - ...CarbohydrateLinkParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 0.1, 20), - sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), -} -export const DefaultCarbohydrateProps = PD.getDefaultValues(CarbohydrateParams) -export type CarbohydrateProps = typeof DefaultCarbohydrateProps +// export const CarbohydrateParams = { +// ...CarbohydrateSymbolParams, +// ...CarbohydrateLinkParams, +// } +// export function getCarbohydrateParams(ctx: ThemeRegistryContext, structure: Structure) { +// return CarbohydrateParams // TODO return copy +// } +// export type CarbohydrateProps = PD.DefaultValues<typeof CarbohydrateParams> -export type CarbohydrateRepresentation = StructureRepresentation<CarbohydrateProps> +// export type CarbohydrateRepresentation = StructureRepresentation<CarbohydrateProps> -export function CarbohydrateRepresentation(): CarbohydrateRepresentation { - return Representation.createMulti('Carbohydrate', CarbohydrateParams, DefaultCarbohydrateProps, [ - ComplexRepresentation('Carbohydrate symbol mesh', CarbohydrateSymbolVisual), - ComplexRepresentation('Carbohydrate link cylinder', CarbohydrateLinkVisual) - ] as StructureRepresentation<CarbohydrateProps>[]) -} \ No newline at end of file +// export function CarbohydrateRepresentation(defaultProps: CarbohydrateProps): CarbohydrateRepresentation { +// return Representation.createMulti('Carbohydrate', defaultProps, [ +// ComplexRepresentation('Carbohydrate symbol mesh', defaultProps, CarbohydrateSymbolVisual), +// ComplexRepresentation('Carbohydrate link cylinder', defaultProps, CarbohydrateLinkVisual) +// ]) +// } \ No newline at end of file diff --git a/src/mol-repr/structure/representation/cartoon.ts b/src/mol-repr/structure/representation/cartoon.ts index 59e0639758375d2600943412da45f82a8ef3a2e2..da2483be5107b99964329c1542ca7de7bb97f0c0 100644 --- a/src/mol-repr/structure/representation/cartoon.ts +++ b/src/mol-repr/structure/representation/cartoon.ts @@ -4,34 +4,48 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { PolymerTraceVisual, PolymerTraceParams } from '../visual/polymer-trace-mesh'; -import { PolymerGapVisual, PolymerGapParams } from '../visual/polymer-gap-cylinder'; -import { NucleotideBlockVisual, NucleotideBlockParams } from '../visual/nucleotide-block-mesh'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; +import { PolymerTraceVisual, PolymerTraceParams, PolymerTraceProps } from '../visual/polymer-trace-mesh'; +import { PolymerGapVisual, PolymerGapParams, PolymerGapProps } from '../visual/polymer-gap-cylinder'; +import { NucleotideBlockVisual, NucleotideBlockParams, NucleotideBlockProps } from '../visual/nucleotide-block-mesh'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { UnitsRepresentation } from '../units-representation'; -import { StructureRepresentation } from '../index'; -import { Representation } from 'mol-repr'; -import { PolymerDirectionVisual, PolymerDirectionParams } from '../visual/polymer-direction-wedge'; +import { StructureRepresentation, StructureRepresentationProvider } from '../representation'; +import { Representation } from 'mol-repr/representation'; +import { PolymerDirectionVisual, PolymerDirectionParams, PolymerDirectionProps } from '../visual/polymer-direction-wedge'; +import { Structure } from 'mol-model/structure'; +import { ThemeRegistryContext } from 'mol-theme/theme'; +import { BuiltInSizeThemeName, BuiltInSizeThemeOptions } from 'mol-theme/size'; +import { BuiltInColorThemeOptions, BuiltInColorThemeName } from 'mol-theme/color'; + +const CartoonVisuals = { + 'polymer-trace': (defaultProps: PolymerTraceProps) => UnitsRepresentation('Polymer trace mesh', defaultProps, PolymerTraceVisual), + 'polymer-gap': (defaultProps: PolymerGapProps) => UnitsRepresentation('Polymer gap cylinder', defaultProps, PolymerGapVisual), + 'nucleotide-block': (defaultProps: NucleotideBlockProps) => UnitsRepresentation('Nucleotide block mesh', defaultProps, NucleotideBlockVisual), + 'direction-wedge': (defaultProps: PolymerDirectionProps) => UnitsRepresentation('Polymer direction wedge', defaultProps, PolymerDirectionVisual) +} +type CartoonVisualName = keyof typeof CartoonVisuals +const CartoonVisualOptions = Object.keys(CartoonVisuals).map(name => [name, name] as [CartoonVisualName, string]) export const CartoonParams = { ...PolymerTraceParams, ...PolymerGapParams, ...NucleotideBlockParams, ...PolymerDirectionParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1), + sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01), + sizeTheme: PD.Select<BuiltInSizeThemeName>('Size Theme', '', 'uniform', BuiltInSizeThemeOptions), + colorTheme: PD.Select<BuiltInColorThemeName>('Color Theme', '', 'polymer-index', BuiltInColorThemeOptions), + visuals: PD.MultiSelect<CartoonVisualName>('Visuals', '', ['polymer-trace', 'polymer-gap', 'nucleotide-block'], CartoonVisualOptions), } -export const DefaultCartoonProps = { ...PD.getDefaultValues(CartoonParams), visuals: [ '0', '1', '2' ] } -export type CartoonProps = typeof DefaultCartoonProps +export function getCartoonParams(ctx: ThemeRegistryContext, structure: Structure) { + return CartoonParams // TODO return copy +} +export type CartoonProps = PD.DefaultValues<typeof CartoonParams> export type CartoonRepresentation = StructureRepresentation<CartoonProps> +export function CartoonRepresentation(defaultProps: CartoonProps): CartoonRepresentation { + return Representation.createMulti('Cartoon', defaultProps, CartoonVisuals as unknown as Representation.Def<CartoonProps>) +} -export function CartoonRepresentation(): CartoonRepresentation { - return Representation.createMulti('Cartoon', CartoonParams, DefaultCartoonProps, [ - UnitsRepresentation('Polymer trace mesh', PolymerTraceVisual), - UnitsRepresentation('Polymer gap cylinder', PolymerGapVisual), - UnitsRepresentation('Nucleotide block mesh', NucleotideBlockVisual), - UnitsRepresentation('Polymer direction wedge', PolymerDirectionVisual) - ] as unknown as StructureRepresentation<CartoonProps>[]) // TODO avoid cast to unknown +export const CartoonRepresentationProvider: StructureRepresentationProvider<typeof CartoonParams> = { + factory: CartoonRepresentation, params: getCartoonParams } \ No newline at end of file diff --git a/src/mol-repr/structure/representation/distance-restraint.ts b/src/mol-repr/structure/representation/distance-restraint.ts index 08ed872669f2632e0d3c9ba64acaeeb7ffc67063..94edde13a8cb99ff0ec108ef8f90f4018a4e99c3 100644 --- a/src/mol-repr/structure/representation/distance-restraint.ts +++ b/src/mol-repr/structure/representation/distance-restraint.ts @@ -1,28 +1,29 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ +// /** +// * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author Alexander Rose <alexander.rose@weirdbyte.de> +// */ -import { CrossLinkRestraintVisual, CrossLinkRestraintParams } from '../visual/cross-link-restraint-cylinder'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { ComplexRepresentation } from '../complex-representation'; -import { StructureRepresentation } from '../index'; -import { Representation } from 'mol-repr'; +// import { CrossLinkRestraintVisual, CrossLinkRestraintParams } from '../visual/cross-link-restraint-cylinder'; +// import { ParamDefinition as PD } from 'mol-util/param-definition'; +// import { ComplexRepresentation } from '../complex-representation'; +// import { StructureRepresentation } from '../representation'; +// import { Representation } from 'mol-repr/representation'; +// import { ThemeRegistryContext } from 'mol-theme/theme'; +// import { Structure } from 'mol-model/structure'; -export const DistanceRestraintParams = { - ...CrossLinkRestraintParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 0.25, 0, 0.05, 20), -} -export const DefaultDistanceRestraintProps = PD.getDefaultValues(DistanceRestraintParams) -export type DistanceRestraintProps = typeof DefaultDistanceRestraintProps +// export const DistanceRestraintParams = { +// ...CrossLinkRestraintParams, +// } +// export function getDistanceRestraintParams(ctx: ThemeRegistryContext, structure: Structure) { +// return DistanceRestraintParams // TODO return copy +// } +// export type DistanceRestraintProps = PD.DefaultValues<typeof DistanceRestraintParams> -export type DistanceRestraintRepresentation = StructureRepresentation<DistanceRestraintProps> +// export type DistanceRestraintRepresentation = StructureRepresentation<DistanceRestraintProps> -export function DistanceRestraintRepresentation(): DistanceRestraintRepresentation { - return Representation.createMulti('Distance restraint', DistanceRestraintParams, DefaultDistanceRestraintProps, [ - ComplexRepresentation('Cross-link restraint', CrossLinkRestraintVisual) - ] as StructureRepresentation<DistanceRestraintProps>[]) -} \ No newline at end of file +// export function DistanceRestraintRepresentation(defaultProps: DistanceRestraintProps): DistanceRestraintRepresentation { +// return Representation.createMulti('Distance restraint', defaultProps, [ +// ComplexRepresentation('Cross-link restraint', defaultProps, CrossLinkRestraintVisual) +// ]) +// } \ No newline at end of file diff --git a/src/mol-repr/structure/representation/molecular-surface.ts b/src/mol-repr/structure/representation/molecular-surface.ts index 0e8fa626b5c7a151ccd1a6a54c5dd347d2cd13dd..b55aa5faedede552c07c3d9aa8aa7e0a671fb2a7 100644 --- a/src/mol-repr/structure/representation/molecular-surface.ts +++ b/src/mol-repr/structure/representation/molecular-surface.ts @@ -1,33 +1,35 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ +// /** +// * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author Alexander Rose <alexander.rose@weirdbyte.de> +// */ -import { GaussianSurfaceVisual, GaussianSurfaceParams } from '../visual/gaussian-surface-mesh'; -import { UnitsRepresentation } from '../units-representation'; -import { GaussianWireframeVisual, GaussianWireframeParams } from '../visual/gaussian-surface-wireframe'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { GaussianDensityVolumeParams, GaussianDensityVolumeVisual } from '../visual/gaussian-density-volume'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; -import { StructureRepresentation } from '../index'; -import { Representation } from 'mol-repr'; +// import { GaussianSurfaceVisual, GaussianSurfaceParams } from '../visual/gaussian-surface-mesh'; +// import { UnitsRepresentation } from '../units-representation'; +// import { GaussianWireframeVisual, GaussianWireframeParams } from '../visual/gaussian-surface-wireframe'; +// import { ParamDefinition as PD } from 'mol-util/param-definition'; +// import { GaussianDensityVolumeParams, GaussianDensityVolumeVisual } from '../visual/gaussian-density-volume'; +// import { StructureRepresentation } from '../representation'; +// import { Representation } from 'mol-repr/representation'; +// import { ThemeRegistryContext } from 'mol-theme/theme'; +// import { Structure } from 'mol-model/structure'; -export const MolecularSurfaceParams = { - ...GaussianSurfaceParams, - ...GaussianWireframeParams, - ...GaussianDensityVolumeParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), -} -export const DefaultMolecularSurfaceProps = { ...PD.getDefaultValues(MolecularSurfaceParams), visuals: [ '0' ] } -export type MolecularSurfaceProps = typeof DefaultMolecularSurfaceProps +// export const MolecularSurfaceParams = { +// ...GaussianSurfaceParams, +// ...GaussianWireframeParams, +// ...GaussianDensityVolumeParams, +// } +// export function getMolecularSurfaceParams(ctx: ThemeRegistryContext, structure: Structure) { +// return MolecularSurfaceParams // TODO return copy +// } +// export type MolecularSurfaceProps = PD.DefaultValues<typeof MolecularSurfaceParams> -export type MolecularSurfaceRepresentation = StructureRepresentation<MolecularSurfaceProps> +// export type MolecularSurfaceRepresentation = StructureRepresentation<MolecularSurfaceProps> -export function MolecularSurfaceRepresentation(): MolecularSurfaceRepresentation { - return Representation.createMulti('Molecular Surface', MolecularSurfaceParams, DefaultMolecularSurfaceProps, [ - UnitsRepresentation('Gaussian surface', GaussianSurfaceVisual), - UnitsRepresentation('Gaussian wireframe', GaussianWireframeVisual), - UnitsRepresentation('Gaussian volume', GaussianDensityVolumeVisual) - ] as unknown as StructureRepresentation<MolecularSurfaceProps>[]) // TODO avoid cast to unknown -} \ No newline at end of file +// export function MolecularSurfaceRepresentation(defaultProps: MolecularSurfaceProps): MolecularSurfaceRepresentation { +// return Representation.createMulti('Molecular Surface', defaultProps, [ +// UnitsRepresentation('Gaussian surface', defaultProps, GaussianSurfaceVisual), +// UnitsRepresentation('Gaussian wireframe', defaultProps, GaussianWireframeVisual), +// UnitsRepresentation('Gaussian volume', defaultProps, GaussianDensityVolumeVisual) +// ]) +// } \ No newline at end of file diff --git a/src/mol-repr/structure/representation/point.ts b/src/mol-repr/structure/representation/point.ts index 0e483ee9e0c8e2e8fff096f68a7289365eb7ce8d..efc91f8df4b9d209ffd7cba231bb777863c8e3fe 100644 --- a/src/mol-repr/structure/representation/point.ts +++ b/src/mol-repr/structure/representation/point.ts @@ -1,25 +1,29 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ +// /** +// * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author Alexander Rose <alexander.rose@weirdbyte.de> +// */ -import { ElementPointVisual, ElementPointParams } from '../visual/element-point'; -import { UnitsRepresentation } from '../units-representation'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { StructureRepresentation } from '../index'; -import { Representation } from 'mol-repr'; +// import { ElementPointVisual, ElementPointParams } from '../visual/element-point'; +// import { UnitsRepresentation } from '../units-representation'; +// import { ParamDefinition as PD } from 'mol-util/param-definition'; +// import { StructureRepresentation } from '../representation'; +// import { Representation } from 'mol-repr/representation'; +// import { ThemeRegistryContext } from 'mol-theme/theme'; +// import { Structure } from 'mol-model/structure'; -export const PointParams = { - ...ElementPointParams, -} -export const DefaultPointProps = PD.getDefaultValues(PointParams) -export type PointProps = typeof DefaultPointProps +// export const PointParams = { +// ...ElementPointParams, +// } +// export function getPointParams(ctx: ThemeRegistryContext, structure: Structure) { +// return PointParams // TODO return copy +// } +// export type PointProps = PD.DefaultValues<typeof PointParams> -export type PointRepresentation = StructureRepresentation<PointProps> +// export type PointRepresentation = StructureRepresentation<PointProps> -export function PointRepresentation(): PointRepresentation { - return Representation.createMulti('Point', PointParams, DefaultPointProps, [ - UnitsRepresentation('Point', ElementPointVisual) - ] as StructureRepresentation<PointProps>[]) -} \ No newline at end of file +// export function PointRepresentation(defaultProps: PointProps): PointRepresentation { +// return Representation.createMulti('Point', defaultProps, [ +// UnitsRepresentation('Point', defaultProps, ElementPointVisual) +// ]) +// } \ No newline at end of file diff --git a/src/mol-repr/structure/representation/spacefill.ts b/src/mol-repr/structure/representation/spacefill.ts index 46a8a3e64d37ced19b1ad30bd09aabc95c83b9b3..42f35ae58b1ed7f670570809e92c1753d01cbb26 100644 --- a/src/mol-repr/structure/representation/spacefill.ts +++ b/src/mol-repr/structure/representation/spacefill.ts @@ -1,25 +1,29 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ +// /** +// * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author Alexander Rose <alexander.rose@weirdbyte.de> +// */ -import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere'; -import { UnitsRepresentation } from '../units-representation'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { StructureRepresentation } from '../index'; -import { Representation } from 'mol-repr'; +// import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere'; +// import { UnitsRepresentation } from '../units-representation'; +// import { ParamDefinition as PD } from 'mol-util/param-definition'; +// import { StructureRepresentation } from '../representation'; +// import { Representation } from 'mol-repr/representation'; +// import { ThemeRegistryContext } from 'mol-theme/theme'; +// import { Structure } from 'mol-model/structure'; -export const SpacefillParams = { - ...ElementSphereParams -} -export const DefaultSpacefillProps = PD.getDefaultValues(SpacefillParams) -export type SpacefillProps = typeof DefaultSpacefillProps +// export const SpacefillParams = { +// ...ElementSphereParams, +// } +// export function getSpacefillParams(ctx: ThemeRegistryContext, structure: Structure) { +// return SpacefillParams // TODO return copy +// } +// export type SpacefillProps = PD.DefaultValues<typeof SpacefillParams> -export type SpacefillRepresentation = StructureRepresentation<SpacefillProps> +// export type SpacefillRepresentation = StructureRepresentation<SpacefillProps> -export function SpacefillRepresentation(): SpacefillRepresentation { - return Representation.createMulti('Spacefill', SpacefillParams, DefaultSpacefillProps, [ - UnitsRepresentation('Sphere mesh', ElementSphereVisual) - ] as StructureRepresentation<SpacefillProps>[]) -} \ No newline at end of file +// export function SpacefillRepresentation(defaultProps: SpacefillProps): SpacefillRepresentation { +// return Representation.createMulti('Spacefill', defaultProps, [ +// UnitsRepresentation('Sphere mesh', defaultProps, ElementSphereVisual) +// ]) +// } \ No newline at end of file diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts index 0b419bc140e3a411bbc0c24c4aa5617ce4e4aaba..3f1b1026dfbd7f9f8504b61fe2bc3a9bd8f6b101 100644 --- a/src/mol-repr/structure/units-representation.ts +++ b/src/mol-repr/structure/units-representation.ts @@ -8,27 +8,27 @@ import { Structure, Unit } from 'mol-model/structure'; import { Task } from 'mol-task' import { RenderObject } from 'mol-gl/render-object'; -import { RepresentationProps, Visual, RepresentationContext } from '..'; +import { RepresentationProps, Visual, RepresentationContext } from '../representation'; import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci'; import { StructureGroup } from './units-visual'; -import { StructureProps, StructureParams, StructureRepresentation } from './index'; +import { StructureProps, StructureRepresentation } from './representation'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; -import { Theme, createTheme } from 'mol-geo/geometry/geometry'; +import { Theme, ThemeProps, createTheme } from 'mol-theme/theme'; export interface UnitsVisual<P extends RepresentationProps = {}> extends Visual<StructureGroup, P> { } -export function UnitsRepresentation<P extends StructureProps>(label: string, visualCtor: () => UnitsVisual<P>): StructureRepresentation<P> { +export function UnitsRepresentation<P extends StructureProps>(label: string, defaultProps: P, visualCtor: () => UnitsVisual<P>): StructureRepresentation<P> { let visuals = new Map<number, { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }>() - let _props: P - let _theme: Theme let _structure: Structure let _groups: ReadonlyArray<Unit.SymmetryGroup> + let _props: P = Object.assign({}, defaultProps) + let _theme: Theme - function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, structure?: Structure) { - _props = Object.assign({}, _props, props, { structure: structure || _structure }) - _theme = createTheme(_props) + function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, structure?: Structure) { + _props = Object.assign({}, _props, props) + _theme = createTheme(ctx, { structure: structure || _structure }, props, themeProps, _theme) return Task.create('Creating or updating UnitsRepresentation', async runtime => { if (!_structure && !structure) { @@ -132,7 +132,6 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis return { label, - params: StructureParams, // TODO get renderObjects() { const renderObjects: RenderObject[] = [] visuals.forEach(({ visual }) => { diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts index 29a00fc88bb991cf23f2c88a0fa9b921bea4d1c1..5ce13b5dc01dfc7e12e5716bfb173a6757f735bc 100644 --- a/src/mol-repr/structure/units-visual.ts +++ b/src/mol-repr/structure/units-visual.ts @@ -5,8 +5,8 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { RepresentationProps, Visual, VisualContext } from '../'; -import { StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams, StructureParams } from './index'; +import { RepresentationProps, Visual, VisualContext } from '../representation'; +import { StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams, StructureParams } from './representation'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; import { MeshRenderObject, PointsRenderObject, LinesRenderObject, DirectVolumeRenderObject } from 'mol-gl/render-object'; import { createUnitsMeshRenderObject, createUnitsPointsRenderObject, createUnitsTransform, createUnitsLinesRenderObject, createUnitsDirectVolumeRenderObject, UnitKind, UnitKindOptions, includesUnitKind } from './visual/util/common'; @@ -14,7 +14,7 @@ import { deepEqual, ValueCell, UUID } from 'mol-util'; import { Interval } from 'mol-data/int'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { RenderableValues } from 'mol-gl/renderable/schema'; -import { Geometry, updateRenderableState, Theme } from 'mol-geo/geometry/geometry'; +import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { createMarkers, MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data'; @@ -24,7 +24,10 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { Points } from 'mol-geo/geometry/points/points'; import { Lines } from 'mol-geo/geometry/lines/lines'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; -import { VisualUpdateState, colorChanged, sizeChanged } from 'mol-repr/util'; +import { VisualUpdateState } from 'mol-repr/util'; +import { Theme } from 'mol-theme/theme'; +import { ColorTheme } from 'mol-theme/color'; +import { SizeTheme } from 'mol-theme/size'; export type StructureGroup = { structure: Structure, group: Unit.SymmetryGroup } @@ -52,7 +55,7 @@ interface UnitsVisualBuilder<P extends UnitsProps, G extends Geometry> { createLocationIterator(group: Unit.SymmetryGroup): LocationIterator getLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number): Loci mark(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean): boolean - setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void + setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme): void } interface UnitsVisualGeometryBuilder<P extends UnitsProps, G extends Geometry> extends UnitsVisualBuilder<P, G> { @@ -68,6 +71,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu let renderObject: UnitsRenderObject | undefined let currentProps: P + let currentTheme: Theme let geometry: Geometry let currentGroup: Unit.SymmetryGroup let currentStructure: Structure @@ -76,6 +80,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu async function create(ctx: VisualContext, group: Unit.SymmetryGroup, theme: Theme, props: Partial<P> = {}) { currentProps = Object.assign({}, defaultProps, props, { structure: currentStructure }) + currentTheme = theme currentGroup = group const unit = group.units[0] @@ -97,7 +102,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu locationIt.reset() VisualUpdateState.reset(updateState) - setUpdateState(updateState, newProps, currentProps) + setUpdateState(updateState, newProps, currentProps, theme, currentTheme) const newConformationId = Unit.conformationId(unit) if (newConformationId !== currentConformationId) { @@ -107,7 +112,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true - if (colorChanged(currentProps, newProps)) updateState.updateColor = true + if (ColorTheme.areEqual(theme.color, currentTheme.color)) updateState.updateColor = true if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true // @@ -143,6 +148,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu updateRenderableState(renderObject.state, newProps) currentProps = newProps + currentTheme = theme } return { @@ -212,9 +218,9 @@ export interface UnitsMeshVisualBuilder<P extends UnitsMeshProps> extends UnitsV export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisualBuilder<P>): UnitsVisual<P> { return UnitsVisual({ ...builder, - setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => { - builder.setUpdateState(state, newProps, currentProps) - if (sizeChanged(currentProps, newProps)) state.createGeometry = true + setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => { + builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme) + if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true }, createEmptyGeometry: Mesh.createEmpty, createRenderObject: createUnitsMeshRenderObject, @@ -237,9 +243,9 @@ export function UnitsPointsVisual<P extends UnitsPointsProps>(builder: UnitsPoin ...builder, createEmptyGeometry: Points.createEmpty, createRenderObject: createUnitsPointsRenderObject, - setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => { - builder.setUpdateState(state, newProps, currentProps) - if (sizeChanged(currentProps, newProps)) state.updateSize = true + setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => { + builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme) + if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.updateSize = true }, updateValues: Points.updateValues }) @@ -260,9 +266,9 @@ export function UnitsLinesVisual<P extends UnitsLinesProps>(builder: UnitsLinesV ...builder, createEmptyGeometry: Lines.createEmpty, createRenderObject: createUnitsLinesRenderObject, - setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => { - builder.setUpdateState(state, newProps, currentProps) - if (sizeChanged(currentProps, newProps)) state.updateSize = true + setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => { + builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme) + if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.updateSize = true }, updateValues: Lines.updateValues }) @@ -283,9 +289,9 @@ export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeProps>(builde ...builder, createEmptyGeometry: DirectVolume.createEmpty, createRenderObject: createUnitsDirectVolumeRenderObject, - setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => { - builder.setUpdateState(state, newProps, currentProps) - if (sizeChanged(currentProps, newProps)) state.createGeometry = true + setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => { + builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme) + if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true }, updateValues: DirectVolume.updateValues }) diff --git a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts index 9654d7b089baa34308453ae38255c723c5a63d78..eed3fe4ff172ece8ef9dd4f6d0739e8eafe78f51 100644 --- a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts @@ -10,7 +10,6 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { createLinkCylinderMesh, LinkCylinderProps, LinkCylinderParams } from './util/link'; import { OrderedSet, Interval } from 'mol-data/int'; import { ComplexMeshVisual, ComplexVisual } from '../complex-visual'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { LinkType } from 'mol-model/structure/model/types'; import { BitFlags } from 'mol-util'; import { UnitsMeshParams } from '../units-visual'; @@ -19,8 +18,8 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { VisualUpdateState } from '../../util'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; // TODO create seperate visual // for (let i = 0, il = carbohydrates.terminalLinks.length; i < il; ++i) { @@ -64,8 +63,9 @@ async function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure: export const CarbohydrateLinkParams = { ...UnitsMeshParams, ...LinkCylinderParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), + // TODO + // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), + // sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), detail: PD.Numeric('Sphere Detail', '', 0, 0, 3, 1), } export const DefaultCarbohydrateLinkProps = PD.getDefaultValues(CarbohydrateLinkParams) diff --git a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts index 2d760f0b10d0b122fa6bb8b28d55470327d4be92..629674d8c151b643eea44cf72ca876e08c38a492 100644 --- a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts +++ b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts @@ -13,19 +13,18 @@ import { DiamondPrism, PentagonalPrism, HexagonalPrism } from 'mol-geo/primitive import { Structure, StructureElement } from 'mol-model/structure'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { getSaccharideShape, SaccharideShapes } from 'mol-model/structure/structure/carbohydrates/constants'; import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; import { ComplexMeshParams, ComplexMeshVisual } from '../complex-visual'; import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { ComplexVisual } from '../index'; +import { ComplexVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; import { OrderedSet, Interval } from 'mol-data/int'; import { EmptyLoci, Loci } from 'mol-model/loci'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; const t = Mat4.identity() const sVec = Vec3.zero() @@ -148,8 +147,9 @@ async function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Struc export const CarbohydrateSymbolParams = { ...ComplexMeshParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 10, 0.1), + // TODO + // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), + // sizeValue: PD.Numeric('Size Value', '', 1, 0, 10, 0.1), detail: PD.Numeric('Sphere Detail', '', 0, 0, 3, 1), } export const DefaultCarbohydrateSymbolProps = PD.getDefaultValues(CarbohydrateSymbolParams) diff --git a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts index 1f37817871e789dbd3ce08395919e4bf522b41b3..711b67717c104b8118698fdf5cdb731924514974 100644 --- a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts +++ b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts @@ -5,22 +5,21 @@ */ import { Link, Structure, StructureElement } from 'mol-model/structure'; -import { ComplexVisual } from '../index'; +import { ComplexVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { LinkCylinderProps, createLinkCylinderMesh, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { ComplexMeshVisual, ComplexMeshParams } from '../complex-visual'; import { Interval } from 'mol-data/int'; -import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; import { BitFlags } from 'mol-util'; import { LinkType } from 'mol-model/structure/model/types'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; async function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) { @@ -54,8 +53,9 @@ async function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structur export const CrossLinkRestraintParams = { ...ComplexMeshParams, ...LinkCylinderParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), + // TODO + // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), + // sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), } export const DefaultCrossLinkRestraintProps = PD.getDefaultValues(CrossLinkRestraintParams) export type CrossLinkRestraintProps = typeof DefaultCrossLinkRestraintProps diff --git a/src/mol-repr/structure/visual/element-point.ts b/src/mol-repr/structure/visual/element-point.ts index 6747ae9f889c15f9fcbdc2af94ad71b8cea30241..c906ac98f0cfce91121b56a95a5c999ee6c46cc9 100644 --- a/src/mol-repr/structure/visual/element-point.ts +++ b/src/mol-repr/structure/visual/element-point.ts @@ -5,22 +5,22 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { getElementLoci, StructureElementIterator, markElement } from './util/element'; import { Vec3 } from 'mol-math/linear-algebra'; -import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; import { UnitsPointsVisual, UnitsPointsParams } from '../units-visual'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Points } from 'mol-geo/geometry/points/points'; import { PointsBuilder } from 'mol-geo/geometry/points/points-builder'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; export const ElementPointParams = { ...UnitsPointsParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 3, 0, 20, 0.1), + // TODO + // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), + // sizeValue: PD.Numeric('Size Value', '', 3, 0, 20, 0.1), pointSizeAttenuation: PD.Boolean('Point Size Attenuation', '', false), } export const DefaultElementPointProps = PD.getDefaultValues(ElementPointParams) diff --git a/src/mol-repr/structure/visual/element-sphere.ts b/src/mol-repr/structure/visual/element-sphere.ts index 73d25eb01ea69f678a8b73c7ecbd1299c5efc3db..29feb54d3bd815bfacd188ba59ce029449d3f505 100644 --- a/src/mol-repr/structure/visual/element-sphere.ts +++ b/src/mol-repr/structure/visual/element-sphere.ts @@ -5,18 +5,18 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { createElementSphereMesh, markElement, getElementLoci, StructureElementIterator } from './util/element'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; export const ElementSphereParams = { ...UnitsMeshParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), + // TODO + // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), + // sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1), + // sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), detail: PD.Numeric('Sphere Detail', '', 0, 0, 3, 1), } export const DefaultElementSphereProps = PD.getDefaultValues(ElementSphereParams) diff --git a/src/mol-repr/structure/visual/gaussian-density-point.ts b/src/mol-repr/structure/visual/gaussian-density-point.ts index 5fd0069f1d7482b63d89baf3118d13b966a72781..2ad030a5cc8a371537e0275d369e6bdcd15f0ae8 100644 --- a/src/mol-repr/structure/visual/gaussian-density-point.ts +++ b/src/mol-repr/structure/visual/gaussian-density-point.ts @@ -5,25 +5,25 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { StructureElementIterator } from './util/element'; import { EmptyLoci } from 'mol-model/loci'; import { Vec3 } from 'mol-math/linear-algebra'; import { UnitsPointsVisual, UnitsPointsParams } from '../units-visual'; -import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Points } from 'mol-geo/geometry/points/points'; import { PointsBuilder } from 'mol-geo/geometry/points/points-builder'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; export const GaussianDensityPointParams = { ...UnitsPointsParams, ...GaussianDensityParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), + // TODO + // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), + // sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), pointSizeAttenuation: PD.Boolean('Point Size Attenuation', '', false), } export const DefaultGaussianDensityPointProps = PD.getDefaultValues(GaussianDensityPointParams) diff --git a/src/mol-repr/structure/visual/gaussian-density-volume.ts b/src/mol-repr/structure/visual/gaussian-density-volume.ts index 89f8b90f0f191a0201e72288c454ffe1c892bdc5..b1afae789263296366672f9e6443ab1119c272f2 100644 --- a/src/mol-repr/structure/visual/gaussian-density-volume.ts +++ b/src/mol-repr/structure/visual/gaussian-density-volume.ts @@ -5,15 +5,15 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { UnitsDirectVolumeVisual, UnitsDirectVolumeParams } from '../units-visual'; import { StructureElementIterator, getElementLoci, markElement } from './util/element'; import { GaussianDensityProps, GaussianDensityParams, computeUnitGaussianDensityTexture } from 'mol-model/structure/structure/unit/gaussian-density'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; async function createGaussianDensityVolume(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, directVolume?: DirectVolume): Promise<DirectVolume> { const { runtime, webgl } = ctx diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index 185cc9a3ce9e89a88755fd0c64d9093378016df6..74bb969be6d7ddc2f84ee739d3fb98f87f78ed65 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -5,7 +5,7 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; import { StructureElementIterator, getElementLoci, markElement } from './util/element'; @@ -13,8 +13,8 @@ import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; async function createGaussianSurfaceMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> { const { smoothness } = props diff --git a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts index b8f0d342e21e49c6743fc60945471b7725d865c8..6cb7e9d4f6242e7a8faa6e77523f842d751702e0 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts @@ -5,17 +5,16 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { UnitsLinesVisual, UnitsLinesParams } from '../units-visual'; import { StructureElementIterator, getElementLoci, markElement } from './util/element'; import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density'; import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { Lines } from 'mol-geo/geometry/lines/lines'; import { computeMarchingCubesLines } from 'mol-geo/util/marching-cubes/algorithm'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, lines?: Lines): Promise<Lines> { const { smoothness } = props @@ -36,8 +35,9 @@ async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure export const GaussianWireframeParams = { ...UnitsLinesParams, ...GaussianDensityParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 2, 0, 10, 0.1), + // TODO + // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), + // sizeValue: PD.Numeric('Size Value', '', 2, 0, 10, 0.1), lineSizeAttenuation: PD.Boolean('Line Size Attenuation', '', false), } export const DefaultGaussianWireframeProps = PD.getDefaultValues(GaussianWireframeParams) diff --git a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts index 7a96419a33dff1f19d4710eb2a24768692e05ccb..5aa8319ec2346f29e121b2b6b1b90131ad0def2f 100644 --- a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts @@ -5,7 +5,7 @@ */ import { Link, Structure, StructureElement } from 'mol-model/structure'; -import { ComplexVisual } from '../index'; +import { ComplexVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; @@ -16,8 +16,8 @@ import { BitFlags } from 'mol-util'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { PickingId } from 'mol-geo/geometry/picking'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; async function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) { const links = structure.links diff --git a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts index 69d2aafd1fc1f377ebe200cd00511dc477d0d439..e177c362db55347c887d80df34823ab4f83a3e0f 100644 --- a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts @@ -6,20 +6,19 @@ */ import { Unit, Link, StructureElement, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { UnitsMeshVisual, UnitsMeshParams, StructureGroup } from '../units-visual'; import { Interval } from 'mol-data/int'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { BitFlags } from 'mol-util'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { PickingId } from 'mol-geo/geometry/picking'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) @@ -67,9 +66,10 @@ async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, s export const IntraUnitLinkParams = { ...UnitsMeshParams, ...LinkCylinderParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), + // TODO + // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), + // sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1), + // sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1), } export const DefaultIntraUnitLinkProps = PD.getDefaultValues(IntraUnitLinkParams) export type IntraUnitLinkProps = typeof DefaultIntraUnitLinkProps diff --git a/src/mol-repr/structure/visual/nucleotide-block-mesh.ts b/src/mol-repr/structure/visual/nucleotide-block-mesh.ts index e92c42fa78d777109294ad211ae44056fd300415..9c341adbb6344dcd91eef82a31da0413566ac6ee 100644 --- a/src/mol-repr/structure/visual/nucleotide-block-mesh.ts +++ b/src/mol-repr/structure/visual/nucleotide-block-mesh.ts @@ -5,7 +5,7 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { Segmentation } from 'mol-data/int'; import { MoleculeType, isNucleic, isPurinBase, isPyrimidineBase } from 'mol-model/structure/model/types'; @@ -17,8 +17,8 @@ import { Box } from 'mol-geo/primitive/box'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; const p1 = Vec3.zero() const p2 = Vec3.zero() @@ -34,10 +34,17 @@ const t = Mat4.identity() const sVec = Vec3.zero() const box = Box() -// TODO define props, should be scalable -async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: {}, mesh?: Mesh) { +export const NucleotideBlockMeshParams = { + sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01), +} +export const DefaultNucleotideBlockMeshProps = PD.getDefaultValues(NucleotideBlockMeshParams) +export type NucleotideBlockMeshProps = typeof DefaultNucleotideBlockMeshProps + +async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: NucleotideBlockMeshProps, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) + const { sizeFactor } = props + // TODO better vertex count estimate const builder = MeshBuilder.create(256, 128, mesh) @@ -64,7 +71,7 @@ async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structu const parentId = modifiedResidues.parentId.get(compId) if (parentId !== undefined) compId = parentId let idx1 = -1, idx2 = -1, idx3 = -1, idx4 = -1, idx5 = -1, idx6 = -1 - let width = 4.5, height = 4.5, depth = 0.5 + let width = 4.5, height = 4.5, depth = 2.5 * sizeFactor if (isPurinBase(compId)) { height = 4.5 @@ -87,7 +94,7 @@ async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structu if (idx5 !== -1 && idx6 !== -1) { pos(idx5, p5); pos(idx6, p6) builder.setGroup(i) - addCylinder(builder, p5, p6, 1, { radiusTop: 0.2, radiusBottom: 0.2 }) + addCylinder(builder, p5, p6, 1, { radiusTop: 1 * sizeFactor, radiusBottom: 1 * sizeFactor }) if (idx1 !== -1 && idx2 !== -1 && idx3 !== -1 && idx4 !== -1) { pos(idx1, p1); pos(idx2, p2); pos(idx3, p3); pos(idx4, p4); Vec3.normalize(v12, Vec3.sub(v12, p2, p1)) @@ -113,7 +120,8 @@ async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structu } export const NucleotideBlockParams = { - ...UnitsMeshParams + ...UnitsMeshParams, + ...NucleotideBlockMeshParams } export const DefaultNucleotideBlockProps = PD.getDefaultValues(NucleotideBlockParams) export type NucleotideBlockProps = typeof DefaultNucleotideBlockProps diff --git a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts index 6e3d2a7ca6965267f8bccedfa4da95500d78dd41..9fab52627114e57d53c43c963ab74aec479d7cfa 100644 --- a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts +++ b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts @@ -5,7 +5,7 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { PolymerBackboneIterator } from './util/polymer'; import { getElementLoci, markElement, StructureElementIterator } from './util/element'; @@ -17,8 +17,8 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { CylinderProps } from 'mol-geo/primitive/cylinder'; import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; export const PolymerBackboneCylinderParams = { radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1), diff --git a/src/mol-repr/structure/visual/polymer-direction-wedge.ts b/src/mol-repr/structure/visual/polymer-direction-wedge.ts index d0f1fe4f5bc51174ea7555d4ef094d4a65931c40..24f5e022ed6a234b6fd161e12eff1c339cfe52c3 100644 --- a/src/mol-repr/structure/visual/polymer-direction-wedge.ts +++ b/src/mol-repr/structure/visual/polymer-direction-wedge.ts @@ -5,18 +5,17 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; -import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { Wedge } from 'mol-geo/primitive/wedge'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; const t = Mat4.identity() const sVec = Vec3.zero() @@ -31,15 +30,16 @@ const heightFactor = 6 const wedge = Wedge() export const PolymerDirectionWedgeParams = { - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), + sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01), } export const DefaultPolymerDirectionWedgeProps = PD.getDefaultValues(PolymerDirectionWedgeParams) export type PolymerDirectionWedgeProps = typeof DefaultPolymerDirectionWedgeProps async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerDirectionWedgeProps, mesh?: Mesh) { const polymerElementCount = unit.polymerElements.length + if (!polymerElementCount) return Mesh.createEmpty(mesh) + const { sizeFactor } = props const vertexCount = polymerElementCount * 24 const builder = MeshBuilder.create(vertexCount, vertexCount / 10, mesh) @@ -62,7 +62,7 @@ async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, s interpolateCurveSegment(state, v, tension, shift) if ((isSheet && !v.secStrucChange) || !isSheet) { - const size = theme.size.size(v.center) + const size = theme.size.size(v.center) * sizeFactor const depth = depthFactor * size const width = widthFactor * size const height = heightFactor * size diff --git a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts index 60585ab0d8965770c9662f1eb28825c750b64bf9..aa69b9bb663b72281429fdd9085934c50ce61559 100644 --- a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts +++ b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts @@ -5,12 +5,11 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { PolymerGapIterator, PolymerGapLocationIterator, markPolymerGapElement, getPolymerGapElementLoci } from './util/polymer'; import { Vec3 } from 'mol-math/linear-algebra'; import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; -import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { LinkCylinderParams } from './util/link'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; @@ -18,12 +17,13 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { CylinderProps } from 'mol-geo/primitive/cylinder'; import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; import { addFixedCountDashedCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; const segmentCount = 10 export const PolymerGapCylinderParams = { + sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01), radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1), } export const DefaultPolymerGapCylinderProps = PD.getDefaultValues(PolymerGapCylinderParams) @@ -33,7 +33,7 @@ async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, stru const polymerGapCount = unit.gapElements.length if (!polymerGapCount) return Mesh.createEmpty(mesh) - const { radialSegments } = props + const { sizeFactor, radialSegments } = props const vertexCountEstimate = segmentCount * radialSegments * 2 * polymerGapCount * 2 const builder = MeshBuilder.create(vertexCountEstimate, vertexCountEstimate / 10, mesh) @@ -57,11 +57,11 @@ async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, stru pos(centerA.element, pA) pos(centerB.element, pB) - cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerA) + cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerA) * sizeFactor builder.setGroup(i) addFixedCountDashedCylinder(builder, pA, pB, 0.5, segmentCount, cylinderProps) - cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerB) + cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerB) * sizeFactor builder.setGroup(i + 1) addFixedCountDashedCylinder(builder, pB, pA, 0.5, segmentCount, cylinderProps) } @@ -78,9 +78,10 @@ async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, stru export const InterUnitLinkParams = { ...UnitsMeshParams, ...LinkCylinderParams, - sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), - sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), - sizeFactor: PD.Numeric('Size Factor', '', 0.3, 0, 10, 0.1), + // TODO + // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions), + // sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), + // sizeFactor: PD.Numeric('Size Factor', '', 0.3, 0, 10, 0.1), } export const DefaultIntraUnitLinkProps = PD.getDefaultValues(InterUnitLinkParams) export type IntraUnitLinkProps = typeof DefaultIntraUnitLinkProps diff --git a/src/mol-repr/structure/visual/polymer-trace-mesh.ts b/src/mol-repr/structure/visual/polymer-trace-mesh.ts index 8f75d29ed49f88e8e72ec399f79b6f6801835a9d..f8c536954ac60e9de49e077c8d139a8ed3c23451 100644 --- a/src/mol-repr/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-repr/structure/visual/polymer-trace-mesh.ts @@ -5,7 +5,7 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { UnitsVisual } from '../index'; +import { UnitsVisual } from '../representation'; import { VisualUpdateState } from '../../util'; import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer'; import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types'; @@ -15,10 +15,11 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { addSheet } from 'mol-geo/geometry/mesh/builder/sheet'; import { addTube } from 'mol-geo/geometry/mesh/builder/tube'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; export const PolymerTraceMeshParams = { + sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01), linearSegments: PD.Numeric('Linear Segments', '', 8, 1, 48, 1), radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1), aspectRatio: PD.Numeric('Aspect Ratio', '', 5, 0.1, 5, 0.1), @@ -33,7 +34,7 @@ async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure: const polymerElementCount = unit.polymerElements.length if (!polymerElementCount) return Mesh.createEmpty(mesh) - const { linearSegments, radialSegments, aspectRatio, arrowFactor } = props + const { sizeFactor, linearSegments, radialSegments, aspectRatio, arrowFactor } = props const vertexCount = linearSegments * radialSegments * polymerElementCount + (radialSegments + 1) * polymerElementCount * 2 const builder = MeshBuilder.create(vertexCount, vertexCount / 10, mesh) @@ -56,7 +57,7 @@ async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure: interpolateCurveSegment(state, v, tension, shift) - let width = theme.size.size(v.center) + let width = theme.size.size(v.center) * sizeFactor if (isCoarse) width *= aspectRatio / 2 if (isSheet) { diff --git a/src/mol-repr/structure/visual/util/common.ts b/src/mol-repr/structure/visual/util/common.ts index 25598d6e34efc0d16031ab5984b1b25f4548f2a8..bff5b88337b5a7d3789e1200f163788d75d165dc 100644 --- a/src/mol-repr/structure/visual/util/common.ts +++ b/src/mol-repr/structure/visual/util/common.ts @@ -5,17 +5,18 @@ */ import { Unit, Structure } from 'mol-model/structure'; -import { StructureProps } from '../../index'; +import { StructureProps } from '../../representation'; import { createMeshRenderObject, createPointsRenderObject, createLinesRenderObject, createDirectVolumeRenderObject } from 'mol-gl/render-object'; import { Mat4 } from 'mol-math/linear-algebra'; import { TransformData, createTransform, createIdentityTransform } from 'mol-geo/geometry/transform-data'; import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { LocationIterator } from 'mol-geo/util/location-iterator'; -import { createRenderableState, Theme } from 'mol-geo/geometry/geometry'; +import { createRenderableState } from 'mol-geo/geometry/geometry'; import { Points } from 'mol-geo/geometry/points/points'; import { Lines } from 'mol-geo/geometry/lines/lines'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; -import { VisualContext } from 'mol-repr'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; export function createUnitsTransform({ units }: Unit.SymmetryGroup, transformData?: TransformData) { const unitCount = units.length diff --git a/src/mol-repr/structure/visual/util/element.ts b/src/mol-repr/structure/visual/util/element.ts index 5bc0407967feadb297c55e6570e0d1549d32398a..9f584171436fadb137e561b26d4553a502f2faae 100644 --- a/src/mol-repr/structure/visual/util/element.ts +++ b/src/mol-repr/structure/visual/util/element.ts @@ -14,8 +14,8 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; import { PickingId } from 'mol-geo/geometry/picking'; import { LocationIterator } from 'mol-geo/util/location-iterator'; -import { VisualContext } from 'mol-repr'; -import { Theme } from 'mol-geo/geometry/geometry'; +import { VisualContext } from 'mol-repr/representation'; +import { Theme } from 'mol-theme/theme'; import { StructureGroup } from 'mol-repr/structure/units-visual'; export interface ElementSphereMeshProps { diff --git a/src/mol-repr/structure/visual/util/link.ts b/src/mol-repr/structure/visual/util/link.ts index 2ea26bff5c8311b488d343fbee6d9e18795eaf6a..a2c04d6251414bde2334ebf3a911740c4687ce32 100644 --- a/src/mol-repr/structure/visual/util/link.ts +++ b/src/mol-repr/structure/visual/util/link.ts @@ -13,7 +13,7 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { CylinderProps } from 'mol-geo/primitive/cylinder'; import { addFixedCountDashedCylinder, addCylinder, addDoubleCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; import { LocationIterator } from 'mol-geo/util/location-iterator'; -import { VisualContext } from 'mol-repr'; +import { VisualContext } from 'mol-repr/representation'; export const LinkCylinderParams = { linkScale: PD.Range('Link Scale', '', 0.4, 0, 1, 0.1), diff --git a/src/mol-repr/util.ts b/src/mol-repr/util.ts index 4db8e0cee7c100f8650074fb216192c9bec3379b..ad7d101646a55f50ca2820049e251d538b4ff006 100644 --- a/src/mol-repr/util.ts +++ b/src/mol-repr/util.ts @@ -7,8 +7,6 @@ import { defaults } from 'mol-util'; import { Structure } from 'mol-model/structure'; import { VisualQuality } from 'mol-geo/geometry/geometry'; -import { SizeProps } from 'mol-geo/geometry/size-data'; -import { ColorProps } from 'mol-geo/geometry/color-data'; export interface VisualUpdateState { updateTransform: boolean @@ -33,24 +31,6 @@ export namespace VisualUpdateState { } } -export function sizeChanged(oldProps: SizeProps, newProps: SizeProps) { - return ( - oldProps.sizeTheme !== newProps.sizeTheme || - oldProps.sizeValue !== newProps.sizeValue || - oldProps.sizeFactor !== newProps.sizeFactor - ) -} - -export function colorChanged(oldProps: ColorProps, newProps: ColorProps) { - return ( - oldProps.colorTheme !== newProps.colorTheme || - oldProps.colorValue !== newProps.colorValue || - oldProps.colorDomain !== newProps.colorDomain || - oldProps.colorList !== newProps.colorList || - oldProps.colorMap !== newProps.colorMap - ) -} - // export interface QualityProps { diff --git a/src/mol-repr/volume/direct-volume.ts b/src/mol-repr/volume/direct-volume.ts index 50e4cc7a210b0e6bdc842251b5b8431f68c6374f..18c0ba431242aa8debc5b756f12b0ea6dd0f3bb0 100644 --- a/src/mol-repr/volume/direct-volume.ts +++ b/src/mol-repr/volume/direct-volume.ts @@ -6,7 +6,7 @@ import { VolumeData } from 'mol-model/volume' import { RuntimeContext } from 'mol-task' -import { VolumeVisual, VolumeRepresentation } from './index'; +import { VolumeVisual, VolumeRepresentation } from './representation'; import { createDirectVolumeRenderObject } from 'mol-gl/render-object'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { ParamDefinition as PD } from 'mol-util/param-definition'; @@ -17,11 +17,12 @@ import { createTexture } from 'mol-gl/webgl/texture'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume'; -import { Geometry, createRenderableState, Theme } from 'mol-geo/geometry/geometry'; +import { Geometry, createRenderableState } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; import { VisualUpdateState } from 'mol-repr/util'; -import { VisualContext, RepresentationContext } from 'mol-repr'; +import { VisualContext, RepresentationContext } from 'mol-repr/representation'; +import { ThemeProps, Theme } from 'mol-theme/theme'; function getBoundingBox(gridDimension: Vec3, transform: Mat4) { const bbox = Box3D.empty() @@ -213,16 +214,15 @@ export function DirectVolumeRepresentation(): VolumeRepresentation<DirectVolumeP const volumeRepr = VolumeRepresentation(DirectVolumeVisual) return { label: 'Direct Volume', - params: DirectVolumeParams, get renderObjects() { return [ ...volumeRepr.renderObjects ] }, get props() { return { ...volumeRepr.props } }, - createOrUpdate: (ctx: RepresentationContext, props: Partial<DirectVolumeProps> = {}, volume?: VolumeData) => { + createOrUpdate: (ctx: RepresentationContext, props: Partial<DirectVolumeProps> = {}, themeProps: ThemeProps = {}, volume?: VolumeData) => { currentProps = Object.assign({}, DefaultDirectVolumeProps, currentProps, props) - return volumeRepr.createOrUpdate(ctx, currentProps, volume) + return volumeRepr.createOrUpdate(ctx, currentProps, themeProps, volume) }, getLoci: (pickingId: PickingId) => { return volumeRepr.getLoci(pickingId) diff --git a/src/mol-repr/volume/isosurface-mesh.ts b/src/mol-repr/volume/isosurface-mesh.ts index 13eb6f3744de657b50995a8c4ab0a736f23d8789..7ba955e50ab9810833ce675569975e8fd81520b3 100644 --- a/src/mol-repr/volume/isosurface-mesh.ts +++ b/src/mol-repr/volume/isosurface-mesh.ts @@ -6,7 +6,7 @@ */ import { VolumeData } from 'mol-model/volume' -import { VolumeVisual, VolumeRepresentation } from './index'; +import { VolumeVisual, VolumeRepresentation } from './representation'; import { createMeshRenderObject } from 'mol-gl/render-object'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { ParamDefinition as PD } from 'mol-util/param-definition'; @@ -14,11 +14,12 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; -import { createRenderableState, Theme } from 'mol-geo/geometry/geometry'; +import { createRenderableState } from 'mol-geo/geometry/geometry'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; import { VisualUpdateState } from 'mol-repr/util'; -import { RepresentationContext, VisualContext } from 'mol-repr'; +import { RepresentationContext, VisualContext } from 'mol-repr/representation'; +import { ThemeProps, Theme } from 'mol-theme/theme'; interface VolumeIsosurfaceProps { isoValueAbsolute: number @@ -72,16 +73,15 @@ export function IsosurfaceRepresentation(): VolumeRepresentation<IsosurfaceProps const volumeRepr = VolumeRepresentation(IsosurfaceVisual) return { label: 'Isosurface', - params: IsosurfaceParams, get renderObjects() { return [ ...volumeRepr.renderObjects ] }, get props() { return { ...volumeRepr.props } }, - createOrUpdate: (ctx: RepresentationContext, props: Partial<IsosurfaceProps> = {}, volume?: VolumeData) => { + createOrUpdate: (ctx: RepresentationContext, props: Partial<IsosurfaceProps> = {}, themeProps: ThemeProps = {}, volume?: VolumeData) => { currentProps = Object.assign({}, DefaultIsosurfaceProps, currentProps, props) - return volumeRepr.createOrUpdate(ctx, currentProps, volume) + return volumeRepr.createOrUpdate(ctx, currentProps, themeProps, volume) }, getLoci: (pickingId: PickingId) => { return volumeRepr.getLoci(pickingId) diff --git a/src/mol-repr/volume/registry.ts b/src/mol-repr/volume/registry.ts new file mode 100644 index 0000000000000000000000000000000000000000..653649b286630970e26b3b536b927d71def5844d --- /dev/null +++ b/src/mol-repr/volume/registry.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { RepresentationProvider, RepresentationRegistry } from '../representation'; +import { VolumeData } from 'mol-model/volume'; + +export class VolumeRepresentationRegistry extends RepresentationRegistry<VolumeData> { + constructor() { + super() + Object.keys(BuiltInVolumeRepresentations).forEach(name => { + const p = (BuiltInVolumeRepresentations as { [k: string]: RepresentationProvider<VolumeData, any> })[name] + this.add(name, p.factory, p.params) + }) + } +} + +export const BuiltInVolumeRepresentations = { + // TODO +} +export type BuiltInVolumeRepresentationsName = keyof typeof BuiltInVolumeRepresentations +export const BuiltInVolumeRepresentationsNames = Object.keys(BuiltInVolumeRepresentations) +export const BuiltInVolumeRepresentationsOptions = BuiltInVolumeRepresentationsNames.map(n => [n, n] as [BuiltInVolumeRepresentationsName, string]) \ No newline at end of file diff --git a/src/mol-repr/volume/index.ts b/src/mol-repr/volume/representation.ts similarity index 94% rename from src/mol-repr/volume/index.ts rename to src/mol-repr/volume/representation.ts index 729f53cff94fda9ccffa9a722ea05f9143ec643f..bca67799d3a48721e4efc251f556ab9cac909f91 100644 --- a/src/mol-repr/volume/index.ts +++ b/src/mol-repr/volume/representation.ts @@ -5,10 +5,10 @@ */ import { Task } from 'mol-task' -import { RepresentationProps, Representation, Visual, RepresentationContext, VisualContext } from '..'; +import { RepresentationProps, Representation, Visual, RepresentationContext, VisualContext, RepresentationProvider } from '../representation'; import { VolumeData, VolumeIsoValue } from 'mol-model/volume'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; -import { Geometry, updateRenderableState, Theme, createTheme } from 'mol-geo/geometry/geometry'; +import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data'; @@ -19,6 +19,7 @@ import { LocationIterator } from 'mol-geo/util/location-iterator'; import { NullLocation } from 'mol-model/location'; import { VisualUpdateState } from 'mol-repr/util'; import { ValueCell } from 'mol-util'; +import { ThemeProps, Theme, createTheme } from 'mol-theme/theme'; export interface VolumeVisual<P extends RepresentationProps = {}> extends Visual<VolumeData, P> { } @@ -134,6 +135,10 @@ export function VolumeVisual<P extends VolumeProps>(builder: VolumeVisualGeometr export interface VolumeRepresentation<P extends RepresentationProps = {}> extends Representation<VolumeData, P> { } +export type VolumeRepresentationProvider<P extends PD.Params> = RepresentationProvider<VolumeData, P> + +// + export const VolumeParams = { ...Geometry.Params, isoValueAbsolute: PD.Range('Iso Value Absolute', '', 0.22, -1, 1, 0.01), @@ -148,9 +153,9 @@ export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeD let _theme: Theme let busy = false - function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, volumeData?: VolumeData) { + function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, volumeData?: VolumeData) { _props = Object.assign({}, DefaultVolumeProps, _props, props) - _theme = createTheme(_props) + _theme = createTheme(ctx, _props, themeProps, {}, _theme) return Task.create('VolumeRepresentation.create', async runtime => { // TODO queue it somehow @@ -173,7 +178,6 @@ export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeD return { label: 'Volume', - params: VolumeParams, get renderObjects() { return visual && visual.renderObject ? [ visual.renderObject ] : [] }, diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts index d087e249c80cbd17e3e30f49102a5bdde537f012..b92620b7c7e8109b03a5ff84cb228c2194865c9d 100644 --- a/src/mol-theme/color.ts +++ b/src/mol-theme/color.ts @@ -4,26 +4,25 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Color, ColorMap } from 'mol-util/color'; -import { Structure } from 'mol-model/structure'; +import { Color } from 'mol-util/color'; import { Location } from 'mol-model/location'; import { ColorType } from 'mol-geo/geometry/color-data'; - -import { ElementIndexColorTheme } from './color/element-index'; -import { CarbohydrateSymbolColorTheme } from './color/carbohydrate-symbol'; -import { ChainIdColorTheme } from './color/chain-id'; -import { ElementSymbolColorTheme } from './color/element-symbol'; -import { UnitIndexColorTheme } from './color/unit-index'; -import { UniformColorTheme } from './color/uniform'; -import { CrossLinkColorTheme } from './color/cross-link'; -import { ShapeGroupColorTheme } from './color/shape-group'; -import { CustomColorTheme } from './color/custom'; -import { ResidueNameColorTheme } from './color/residue-name'; -import { SequenceIdColorTheme } from './color/sequence-id'; -import { SecondaryStructureColorTheme } from './color/secondary-structure'; -import { MoleculeTypeColorTheme } from './color/molecule-type'; -import { PolymerIndexColorTheme } from './color/polymer-index'; -import { ColorMatplotlib, ColorBrewer, ColorOther } from 'mol-util/color/tables'; +import { CarbohydrateSymbolColorThemeProvider } from './color/carbohydrate-symbol'; +import { UniformColorTheme, UniformColorThemeProvider } from './color/uniform'; +import { deepEqual } from 'mol-util'; +import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { ThemeDataContext } from 'mol-theme/theme'; +import { ChainIdColorThemeProvider } from './color/chain-id'; +import { CrossLinkColorThemeProvider } from './color/cross-link'; +import { ElementIndexColorThemeProvider } from './color/element-index'; +import { ElementSymbolColorThemeProvider } from './color/element-symbol'; +import { MoleculeTypeColorThemeProvider } from './color/molecule-type'; +import { PolymerIndexColorThemeProvider } from './color/polymer-index'; +import { ResidueNameColorThemeProvider } from './color/residue-name'; +import { SecondaryStructureColorThemeProvider } from './color/secondary-structure'; +import { SequenceIdColorThemeProvider } from './color/sequence-id'; +import { ShapeGroupColorThemeProvider } from './color/shape-group'; +import { UnitIndexColorThemeProvider } from './color/unit-index'; export type LocationColor = (location: Location, isSecondary: boolean) => Color @@ -37,29 +36,6 @@ export function ScaleLegend(minLabel: string, maxLabel: string, colors: Color[]) return { kind: 'scale-legend', minLabel, maxLabel, colors } } -export type ColorScaleName = ( - 'default' | - keyof typeof ColorBrewer | keyof typeof ColorMatplotlib | keyof typeof ColorOther -) -export const ColorScaleNames = [ - 'default', - ...Object.keys(ColorBrewer), ...Object.keys(ColorMatplotlib), ...Object.keys(ColorOther) -] -export const ColorScaleOptions = ColorScaleNames.map(n => [n, n] as [ColorScaleName, string]) - -export function getColorScaleFromName(name: string) { - if (name === 'default') { - return - } else if (name in ColorBrewer) { - return ColorBrewer[name as keyof typeof ColorBrewer] - } else if (name in ColorMatplotlib) { - return ColorMatplotlib[name as keyof typeof ColorMatplotlib] - } else if (name in ColorOther) { - return ColorOther[name as keyof typeof ColorOther] - } - console.warn(`unknwon color list named '${name}'`) -} - export interface TableLegend { kind: 'table-legend' table: [ string, Color ][] @@ -68,77 +44,76 @@ export function TableLegend(table: [ string, Color ][]): TableLegend { return { kind: 'table-legend', table } } -export interface ColorThemeFeatures { - /** Does allow providing a structure object */ - structure?: boolean - /** Does allow providing a volume object */ - volume?: boolean - /** Does allow providing a list of colors (for creating a scale) */ - list?: boolean - /** Does allow providing a map of colors */ - map?: boolean - /** Does allow providing the boundaries for the scale */ - domain?: boolean - /** Does allow providing a single/special color value */ - value?: boolean -} +export type ColorThemeProps = { [k: string]: any } -export interface ColorTheme { - features: ColorThemeFeatures - granularity: ColorType - color: LocationColor - description?: string - legend?: ScaleLegend | TableLegend +export { ColorTheme } +interface ColorTheme<P extends ColorThemeProps = {}> { + readonly granularity: ColorType + readonly color: LocationColor + readonly props: Readonly<P> + readonly description?: string + readonly legend?: Readonly<ScaleLegend | TableLegend> } +namespace ColorTheme { + export type Props = { [k: string]: any } + export const Empty = UniformColorTheme({}, { value: Color(0xCCCCCC) }) -export function ColorTheme(props: ColorThemeProps): ColorTheme { - switch (props.name) { - case 'carbohydrate-symbol': return CarbohydrateSymbolColorTheme(props) - case 'chain-id': return ChainIdColorTheme(props) - case 'cross-link': return CrossLinkColorTheme(props) - case 'custom': return CustomColorTheme(props) - case 'element-index': return ElementIndexColorTheme(props) - case 'element-symbol': return ElementSymbolColorTheme(props) - case 'molecule-type': return MoleculeTypeColorTheme(props) - case 'polymer-index': return PolymerIndexColorTheme(props) - case 'residue-name': return ResidueNameColorTheme(props) - case 'secondary-structure': return SecondaryStructureColorTheme(props) - case 'sequence-id': return SequenceIdColorTheme(props) - case 'shape-group': return ShapeGroupColorTheme(props) - case 'unit-index': return UnitIndexColorTheme(props) - case 'uniform': return UniformColorTheme(props) + export function areEqual(themeA: ColorTheme, themeB: ColorTheme) { + return themeA === themeB && deepEqual(themeA.props, themeB.props) } -} -export interface ColorThemeProps { - name: ColorThemeName - domain?: [number, number] - value?: Color - list?: Color[] - map?: ColorMap<any> - structure?: Structure - color?: LocationColor - granularity?: ColorType, - description?: string, - legend?: ScaleLegend | TableLegend + export interface Provider<P extends PD.Params> { + readonly factory: (ctx: ThemeDataContext, props: PD.DefaultValues<P>) => ColorTheme<PD.DefaultValues<P>> + readonly params: (ctx: ThemeDataContext) => P + } + + export class Registry { + private _list: { name: string, provider: Provider<any> }[] = [] + private _map = new Map<string, Provider<any>>() + + constructor() { + Object.keys(BuiltInColorThemes).forEach(name => { + const p = (BuiltInColorThemes as { [k: string]: Provider<any> })[name] + this.add(name, p.factory, p.params) + }) + } + + add<P extends PD.Params>(name: string, factory: Provider<P>['factory'], params: Provider<P>['params']) { + const provider = { factory, params } as Provider<P> + this._list.push({ name, provider }) + this._map.set(name, provider) + } + + get(id: string) { + return this._map.get(id) + } + + create(id: string, ctx: ThemeDataContext, props = {}) { + const provider = this.get(id) + return provider ? provider.factory(ctx, { ...PD.getDefaultValues(provider.params(ctx)), ...props }) : Empty + } + + get list() { + return this._list + } + } } -export const ColorThemeInfo = { - 'carbohydrate-symbol': {}, - 'chain-id': {}, - 'cross-link': {}, - 'custom': {}, - 'element-index': {}, - 'element-symbol': {}, - 'molecule-type': {}, - 'polymer-index': {}, - 'residue-name': {}, - 'secondary-structure': {}, - 'sequence-id': {}, - 'shape-group': {}, - 'unit-index': {}, - 'uniform': {}, +export const BuiltInColorThemes = { + 'carbohydrate-symbol': CarbohydrateSymbolColorThemeProvider, + 'chain-id': ChainIdColorThemeProvider, + 'cross-link': CrossLinkColorThemeProvider, + 'element-index': ElementIndexColorThemeProvider, + 'element-symbol': ElementSymbolColorThemeProvider, + 'molecule-type': MoleculeTypeColorThemeProvider, + 'polymer-index': PolymerIndexColorThemeProvider, + 'residue-name': ResidueNameColorThemeProvider, + 'secondary-structure': SecondaryStructureColorThemeProvider, + 'sequence-id': SequenceIdColorThemeProvider, + 'shape-group': ShapeGroupColorThemeProvider, + 'unit-index': UnitIndexColorThemeProvider, + 'uniform': UniformColorThemeProvider, } -export type ColorThemeName = keyof typeof ColorThemeInfo -export const ColorThemeNames = Object.keys(ColorThemeInfo) -export const ColorThemeOptions = ColorThemeNames.map(n => [n, n] as [ColorThemeName, string]) \ No newline at end of file +export type BuiltInColorThemeName = keyof typeof BuiltInColorThemes +export const BuiltInColorThemeNames = Object.keys(BuiltInColorThemes) +export const BuiltInColorThemeOptions = BuiltInColorThemeNames.map(n => [n, n] as [BuiltInColorThemeName, string]) \ No newline at end of file diff --git a/src/mol-theme/color/carbohydrate-symbol.ts b/src/mol-theme/color/carbohydrate-symbol.ts index a21853d87f941f899f7071ff3260b55b9d346541..24940f7a6e813e9c837e738615758ca21b02304f 100644 --- a/src/mol-theme/color/carbohydrate-symbol.ts +++ b/src/mol-theme/color/carbohydrate-symbol.ts @@ -8,17 +8,34 @@ import { StructureElement, Link, ElementIndex, Unit } from 'mol-model/structure' import { SaccharideColors, MonosaccharidesColorTable } from 'mol-model/structure/structure/carbohydrates/constants'; import { Location } from 'mol-model/location'; -import { ColorThemeProps, ColorTheme, LocationColor, TableLegend } from '../color'; +import { ColorTheme, LocationColor, TableLegend } from '../color'; import { Color } from 'mol-util/color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; const DefaultColor = Color(0xCCCCCC) const Description = 'Assigns colors according to the Symbol Nomenclature for Glycans (SNFG).' -export function CarbohydrateSymbolColorTheme(props: ColorThemeProps): ColorTheme { +// name: ColorThemeName +// domain?: [number, number] +// value?: Color +// list?: Color[] +// map?: ColorMap<any> + +export const CarbohydrateSymbolColorThemeParams = { + // domain: PD.Interval('Color Domain', '', [0, 1]), + // value: PD.Color('Color Value', '', DefaultColor), +} +export function getCarbohydrateSymbolColorThemeParams(ctx: ThemeDataContext) { + return CarbohydrateSymbolColorThemeParams // TODO return copy +} +export type CarbohydrateSymbolColorThemeProps = PD.DefaultValues<typeof CarbohydrateSymbolColorThemeParams> + +export function CarbohydrateSymbolColorTheme(ctx: ThemeDataContext, props: CarbohydrateSymbolColorThemeProps): ColorTheme<CarbohydrateSymbolColorThemeProps> { let color: LocationColor - if (props.structure) { - const { elements, getElementIndex, getAnomericCarbon } = props.structure.carbohydrates + if (ctx.structure) { + const { elements, getElementIndex, getAnomericCarbon } = ctx.structure.carbohydrates const getColor = (unit: Unit, index: ElementIndex) => { const residueIndex = unit.model.atomicHierarchy.residueAtomSegments.index[index] @@ -47,10 +64,14 @@ export function CarbohydrateSymbolColorTheme(props: ColorThemeProps): ColorTheme } return { - features: {}, granularity: 'group', color: color, + props: props, description: Description, legend: TableLegend(MonosaccharidesColorTable) } +} + +export const CarbohydrateSymbolColorThemeProvider: ColorTheme.Provider<typeof CarbohydrateSymbolColorThemeParams> = { + factory: CarbohydrateSymbolColorTheme, params: getCarbohydrateSymbolColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/chain-id.ts b/src/mol-theme/color/chain-id.ts index c91825e4729d16b1777eceb17796f75906109baf..90045dc3a4a795a072b1b88726bb6c9227405d83 100644 --- a/src/mol-theme/color/chain-id.ts +++ b/src/mol-theme/color/chain-id.ts @@ -8,11 +8,22 @@ import { Unit, StructureProperties, StructureElement, Link } from 'mol-model/str import { ColorScale, Color } from 'mol-util/color'; import { Location } from 'mol-model/location'; -import { ColorThemeProps, ColorTheme, LocationColor } from '../color'; +import { ColorTheme, LocationColor } from '../color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; +import { ColorListOptions, ColorListName } from 'mol-util/color/scale'; const DefaultColor = Color(0xCCCCCC) const Description = 'Gives every chain a color based on its `asym_id` value.' +export const ChainIdColorThemeParams = { + list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions), +} +export function getChainIdColorThemeParams(ctx: ThemeDataContext) { + return ChainIdColorThemeParams // TODO return copy +} +export type ChainIdColorThemeProps = PD.DefaultValues<typeof ChainIdColorThemeParams> + function getAsymId(unit: Unit): StructureElement.Property<string> { switch (unit.kind) { case Unit.Kind.Atomic: @@ -23,14 +34,13 @@ function getAsymId(unit: Unit): StructureElement.Property<string> { } } -export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme { +export function ChainIdColorTheme(ctx: ThemeDataContext, props: ChainIdColorThemeProps): ColorTheme<ChainIdColorThemeProps> { let color: LocationColor - const scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' }) - // const table: [string, Color][] = [] + const scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' }) - if (props.structure) { + if (ctx.structure) { const l = StructureElement.create() - const { models } = props.structure + const { models } = ctx.structure const asymIdSerialMap = new Map<string, number>() let j = 0 for (let i = 0, il = models.length; i <il; ++i) { @@ -44,8 +54,6 @@ export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme { scale.setDomain(0, asymIdSerialMap.size - 1) const scaleColor = scale.color - // asymIdSerialMap.forEach((v, k) => table.push([k, scaleColor(v)])) - color = (location: Location): Color => { if (StructureElement.isLocation(location)) { const asym_id = getAsymId(location.unit) @@ -63,11 +71,14 @@ export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: { structure: true, list: true }, granularity: 'group', color, + props, description: Description, - // legend: scale ? TableLegend(table) : undefined legend: scale ? scale.legend : undefined } +} + +export const ChainIdColorThemeProvider: ColorTheme.Provider<typeof ChainIdColorThemeParams> = { + factory: ChainIdColorTheme, params: getChainIdColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/cross-link.ts b/src/mol-theme/color/cross-link.ts index d24b79e4a92b4e45f7f887df5e333066f0be69c0..031c57eeff17860c584b2fb3e6c8f8f26accd22e 100644 --- a/src/mol-theme/color/cross-link.ts +++ b/src/mol-theme/color/cross-link.ts @@ -8,14 +8,24 @@ import { Link } from 'mol-model/structure'; import { Color, ColorScale } from 'mol-util/color'; import { Location } from 'mol-model/location'; -import { ColorThemeProps, ColorTheme, LocationColor } from '../color'; +import { ColorTheme, LocationColor } from '../color'; import { Vec3 } from 'mol-math/linear-algebra'; -import { ColorBrewer } from 'mol-util/color/tables'; -import { defaults } from 'mol-util'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; +import { ColorListName, ColorListOptions } from 'mol-util/color/scale'; const DefaultColor = Color(0xCCCCCC) const Description = 'Colors cross-links by the deviation of the observed distance versus the modeled distance (e.g. `ihm_cross_link_restraint.distance_threshold`).' +export const CrossLinkColorThemeParams = { + domain: PD.Interval('Color Domain', '', [-10, 10]), + list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions), +} +export function getCrossLinkColorThemeParams(ctx: ThemeDataContext) { + return CrossLinkColorThemeParams // TODO return copy +} +export type CrossLinkColorThemeProps = PD.DefaultValues<typeof CrossLinkColorThemeParams> + const distVecA = Vec3.zero(), distVecB = Vec3.zero() function linkDistance(link: Link.Location) { link.aUnit.conformation.position(link.aIndex, distVecA) @@ -23,15 +33,15 @@ function linkDistance(link: Link.Location) { return Vec3.distance(distVecA, distVecB) } -export function CrossLinkColorTheme(props: ColorThemeProps): ColorTheme { +export function CrossLinkColorTheme(ctx: ThemeDataContext, props: CrossLinkColorThemeProps): ColorTheme<CrossLinkColorThemeProps> { let color: LocationColor let scale: ColorScale | undefined = undefined - if (props.structure) { - const crosslinks = props.structure.crossLinkRestraints + if (ctx.structure) { + const crosslinks = ctx.structure.crossLinkRestraints scale = ColorScale.create({ - domain: defaults(props.domain, [ -10, 10 ]), - list: defaults(props.list, ColorBrewer.RdYlBu) + domain: props.domain, + listOrName: props.list }) const scaleColor = scale.color @@ -49,10 +59,14 @@ export function CrossLinkColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: { list: true, domain: true, structure: true }, granularity: 'group', color, + props, description: Description, legend: scale ? scale.legend : undefined } +} + +export const CrossLinkColorThemeProvider: ColorTheme.Provider<typeof CrossLinkColorThemeParams> = { + factory: CrossLinkColorTheme, params: getCrossLinkColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/custom.ts b/src/mol-theme/color/custom.ts deleted file mode 100644 index 4eb5a10ea4497ba5c419607e1467245b4758dc0e..0000000000000000000000000000000000000000 --- a/src/mol-theme/color/custom.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { Color } from 'mol-util/color'; -import { ColorThemeProps, ColorTheme } from '../color'; -import { defaults } from 'mol-util'; - -const DefaultColor = Color(0xCCCCCC) - -export function CustomColorTheme(props: ColorThemeProps): ColorTheme { - const value = defaults(props.value, DefaultColor) - return { - features: {}, - granularity: defaults(props.granularity, 'uniform'), - color: defaults(props.color, () => value), - description: props.description, - legend: props.legend - } -} \ No newline at end of file diff --git a/src/mol-theme/color/element-index.ts b/src/mol-theme/color/element-index.ts index 2ba30ce687307d87d5caa9fb34a9db98c71c4e91..68264878048d981b7e93296a629113c13222022b 100644 --- a/src/mol-theme/color/element-index.ts +++ b/src/mol-theme/color/element-index.ts @@ -8,17 +8,28 @@ import { ColorScale, Color } from 'mol-util/color'; import { Location } from 'mol-model/location'; import { StructureElement, Link } from 'mol-model/structure'; import { OrderedSet } from 'mol-data/int'; -import { ColorThemeProps, ColorTheme, LocationColor } from '../color'; +import { ColorTheme, LocationColor } from '../color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; +import { ColorListOptions, ColorListName } from 'mol-util/color/scale'; const DefaultColor = Color(0xCCCCCC) const Description = 'Gives every element (atom or coarse sphere/gaussian) a unique color based on the position (index) of the element in the list of elements in the structure.' -export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme { +export const ElementIndexColorThemeParams = { + list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions), +} +export function getElementIndexColorThemeParams(ctx: ThemeDataContext) { + return ElementIndexColorThemeParams // TODO return copy +} +export type ElementIndexColorThemeProps = PD.DefaultValues<typeof ElementIndexColorThemeParams> + +export function ElementIndexColorTheme(ctx: ThemeDataContext, props: ElementIndexColorThemeProps): ColorTheme<ElementIndexColorThemeProps> { let color: LocationColor - let scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' }) + let scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' }) - if (props.structure) { - const { units } = props.structure + if (ctx.structure) { + const { units } = ctx.structure const unitCount = units.length const cummulativeElementCount = new Map<number, number>() const unitIdIndex = new Map<number, number>() @@ -48,10 +59,14 @@ export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: { structure: true, list: true }, granularity: 'groupInstance', color, + props, description: Description, legend: scale ? scale.legend : undefined } +} + +export const ElementIndexColorThemeProvider: ColorTheme.Provider<typeof ElementIndexColorThemeParams> = { + factory: ElementIndexColorTheme, params: getElementIndexColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/element-symbol.ts b/src/mol-theme/color/element-symbol.ts index 8d7f87b21d0d99e686fea90c4011a3df572d7b2d..8c5d2bb095de8e752289d60c33e263a35fcc326e 100644 --- a/src/mol-theme/color/element-symbol.ts +++ b/src/mol-theme/color/element-symbol.ts @@ -8,7 +8,9 @@ import { ElementSymbol } from 'mol-model/structure/model/types'; import { Color, ColorMap } from 'mol-util/color'; import { StructureElement, Unit, Link } from 'mol-model/structure'; import { Location } from 'mol-model/location'; -import { ColorThemeProps, ColorTheme, TableLegend } from '../color'; +import { ColorTheme, TableLegend } from '../color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; // from Jmol http://jmol.sourceforge.net/jscolors/ (or 0xFFFFFF) export const ElementSymbolColors = ColorMap({ @@ -18,12 +20,18 @@ export const ElementSymbolColors = ColorMap({ const DefaultElementSymbolColor = Color(0xFFFFFF) const Description = 'Assigns a color to every atom according to its chemical element.' +export const ElementSymbolColorThemeParams = {} +export function getElementSymbolColorThemeParams(ctx: ThemeDataContext) { + return ElementSymbolColorThemeParams // TODO return copy +} +export type ElementSymbolColorThemeProps = PD.DefaultValues<typeof ElementSymbolColorThemeParams> + export function elementSymbolColor(element: ElementSymbol): Color { const c = (ElementSymbolColors as { [k: string]: Color })[element]; return c === undefined ? DefaultElementSymbolColor : c } -export function ElementSymbolColorTheme(props: ColorThemeProps): ColorTheme { +export function ElementSymbolColorTheme(ctx: ThemeDataContext, props: ElementSymbolColorThemeProps): ColorTheme<ElementSymbolColorThemeProps> { function color(location: Location): Color { if (StructureElement.isLocation(location)) { if (Unit.isAtomic(location.unit)) { @@ -40,12 +48,16 @@ export function ElementSymbolColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: {}, granularity: 'group', color, + props, description: Description, legend: TableLegend(Object.keys(ElementSymbolColors).map(name => { return [name, (ElementSymbolColors as any)[name] as Color] as [string, Color] })) } +} + +export const ElementSymbolColorThemeProvider: ColorTheme.Provider<typeof ElementSymbolColorThemeParams> = { + factory: ElementSymbolColorTheme, params: getElementSymbolColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/molecule-type.ts b/src/mol-theme/color/molecule-type.ts index 9bdc21d39a52dae10358d5f0d3c61feda2cabd44..18dd0440caf9890fd1ffeb02b71d844cd98e8034 100644 --- a/src/mol-theme/color/molecule-type.ts +++ b/src/mol-theme/color/molecule-type.ts @@ -7,9 +7,11 @@ import { Color, ColorMap } from 'mol-util/color'; import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure'; import { Location } from 'mol-model/location'; -import { ColorThemeProps, ColorTheme, TableLegend } from '../color'; +import { ColorTheme, TableLegend } from '../color'; import { MoleculeType } from 'mol-model/structure/model/types'; import { getElementMoleculeType } from 'mol-model/structure/util'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; const MoleculeTypeColors = ColorMap({ water: 0x386cb0, @@ -24,6 +26,12 @@ const MoleculeTypeColors = ColorMap({ const DefaultMoleculeTypeColor = Color(0xffff99) const Description = 'Assigns a color based on the molecule type of a residue.' +export const MoleculeTypeColorThemeParams = {} +export function getMoleculeTypeColorThemeParams(ctx: ThemeDataContext) { + return MoleculeTypeColorThemeParams // TODO return copy +} +export type MoleculeTypeColorThemeProps = PD.DefaultValues<typeof MoleculeTypeColorThemeParams> + export function moleculeTypeColor(unit: Unit, element: ElementIndex): Color { const moleculeType = getElementMoleculeType(unit, element) switch (moleculeType) { @@ -38,7 +46,7 @@ export function moleculeTypeColor(unit: Unit, element: ElementIndex): Color { return DefaultMoleculeTypeColor } -export function MoleculeTypeColorTheme(props: ColorThemeProps): ColorTheme { +export function MoleculeTypeColorTheme(ctx: ThemeDataContext, props: MoleculeTypeColorThemeProps): ColorTheme<MoleculeTypeColorThemeProps> { function color(location: Location): Color { if (StructureElement.isLocation(location)) { return moleculeTypeColor(location.unit, location.element) @@ -49,12 +57,16 @@ export function MoleculeTypeColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: {}, granularity: 'group', color, + props, description: Description, legend: TableLegend(Object.keys(MoleculeTypeColors).map(name => { return [name, (MoleculeTypeColors as any)[name] as Color] as [string, Color] }).concat([[ 'Other/unknown', DefaultMoleculeTypeColor ]])) } +} + +export const MoleculeTypeColorThemeProvider: ColorTheme.Provider<typeof MoleculeTypeColorThemeParams> = { + factory: MoleculeTypeColorTheme, params: getMoleculeTypeColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/polymer-index.ts b/src/mol-theme/color/polymer-index.ts index b17a57dfe8a526c52dc1de93d0e5cee1ba558c0f..4b54924ef469aca559fc65b70b55886f21cd5755 100644 --- a/src/mol-theme/color/polymer-index.ts +++ b/src/mol-theme/color/polymer-index.ts @@ -7,17 +7,28 @@ import { ColorScale, Color } from 'mol-util/color'; import { Location } from 'mol-model/location'; import { StructureElement, Link } from 'mol-model/structure'; -import { ColorTheme, ColorThemeProps, LocationColor } from '../color'; +import { ColorTheme, LocationColor } from '../color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; +import { ColorListName, ColorListOptions } from 'mol-util/color/scale'; const DefaultColor = Color(0xCCCCCC) const Description = 'Gives every polymer a unique color based on the position (index) of the polymer in the list of polymers in the structure.' -export function PolymerIndexColorTheme(props: ColorThemeProps): ColorTheme { +export const PolymerIndexColorThemeParams = { + list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions), +} +export function getPolymerIndexColorThemeParams(ctx: ThemeDataContext) { + return PolymerIndexColorThemeParams // TODO return copy +} +export type PolymerIndexColorThemeProps = PD.DefaultValues<typeof PolymerIndexColorThemeParams> + +export function PolymerIndexColorTheme(ctx: ThemeDataContext, props: PolymerIndexColorThemeProps): ColorTheme<PolymerIndexColorThemeProps> { let color: LocationColor - const scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' }) + const scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' }) - if (props.structure) { - const { units } = props.structure + if (ctx.structure) { + const { units } = ctx.structure let polymerCount = 0 for (let i = 0, il = units.length; i <il; ++i) { if (units[i].polymerElements.length > 0) ++polymerCount @@ -45,10 +56,14 @@ export function PolymerIndexColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: { structure: true, list: true }, granularity: 'instance', color, + props, description: Description, legend: scale ? scale.legend : undefined } +} + +export const PolymerIndexColorThemeProvider: ColorTheme.Provider<typeof PolymerIndexColorThemeParams> = { + factory: PolymerIndexColorTheme, params: getPolymerIndexColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/residue-name.ts b/src/mol-theme/color/residue-name.ts index 756ef8c482458704ceaca1f097cfbe8f9fa9216a..ec2a645feacd0e73b395fd0fbc438f229354ab3b 100644 --- a/src/mol-theme/color/residue-name.ts +++ b/src/mol-theme/color/residue-name.ts @@ -7,7 +7,9 @@ import { Color, ColorMap } from 'mol-util/color'; import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure'; import { Location } from 'mol-model/location'; -import { ColorThemeProps, ColorTheme, TableLegend } from '../color'; +import { ColorTheme, TableLegend } from '../color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; // protein colors from Jmol http://jmol.sourceforge.net/jscolors/ const ResidueNameColors = ColorMap({ @@ -59,6 +61,12 @@ const ResidueNameColors = ColorMap({ const DefaultResidueNameColor = Color(0xFF00FF) const Description = 'Assigns a color to every residue according to its name.' +export const ResidueNameColorThemeParams = {} +export function getResidueNameColorThemeParams(ctx: ThemeDataContext) { + return ResidueNameColorThemeParams // TODO return copy +} +export type ResidueNameColorThemeProps = PD.DefaultValues<typeof ResidueNameColorThemeParams> + export function residueNameColor(residueName: string): Color { const c = (ResidueNameColors as { [k: string]: Color })[residueName]; return c === undefined ? DefaultResidueNameColor : c @@ -84,7 +92,7 @@ function getCoarseCompId(unit: Unit.Spheres | Unit.Gaussians, element: ElementIn } } -export function ResidueNameColorTheme(props: ColorThemeProps): ColorTheme { +export function ResidueNameColorTheme(ctx: ThemeDataContext, props: ResidueNameColorThemeProps): ColorTheme<ResidueNameColorThemeProps> { function color(location: Location): Color { if (StructureElement.isLocation(location)) { if (Unit.isAtomic(location.unit)) { @@ -105,12 +113,16 @@ export function ResidueNameColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: {}, granularity: 'group', color, + props, description: Description, legend: TableLegend(Object.keys(ResidueNameColors).map(name => { return [name, (ResidueNameColors as any)[name] as Color] as [string, Color] }).concat([[ 'Unknown', DefaultResidueNameColor ]])) } +} + +export const ResidueNameColorThemeProvider: ColorTheme.Provider<typeof ResidueNameColorThemeParams> = { + factory: ResidueNameColorTheme, params: getResidueNameColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/secondary-structure.ts b/src/mol-theme/color/secondary-structure.ts index d9a6fd7b6e15518dd354c721417e7e1c73ca75b6..b53171be85c73d1c7209d571a127bc19c8371670 100644 --- a/src/mol-theme/color/secondary-structure.ts +++ b/src/mol-theme/color/secondary-structure.ts @@ -7,9 +7,11 @@ import { Color, ColorMap } from 'mol-util/color'; import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure'; import { Location } from 'mol-model/location'; -import { ColorThemeProps, ColorTheme, TableLegend } from '../color'; +import { ColorTheme, TableLegend } from '../color'; import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types'; import { getElementMoleculeType } from 'mol-model/structure/util'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; // from Jmol http://jmol.sourceforge.net/jscolors/ (shapely) const SecondaryStructureColors = ColorMap({ @@ -29,6 +31,12 @@ const SecondaryStructureColors = ColorMap({ const DefaultSecondaryStructureColor = Color(0x808080) const Description = 'Assigns a color based on the type of secondary structure and basic molecule type.' +export const SecondaryStructureColorThemeParams = {} +export function getSecondaryStructureColorThemeParams(ctx: ThemeDataContext) { + return SecondaryStructureColorThemeParams // TODO return copy +} +export type SecondaryStructureColorThemeProps = PD.DefaultValues<typeof SecondaryStructureColorThemeParams> + export function secondaryStructureColor(unit: Unit, element: ElementIndex): Color { let secStrucType = SecondaryStructureType.create(SecondaryStructureType.Flag.None) if (Unit.isAtomic(unit)) { @@ -61,7 +69,7 @@ export function secondaryStructureColor(unit: Unit, element: ElementIndex): Colo return DefaultSecondaryStructureColor } -export function SecondaryStructureColorTheme(props: ColorThemeProps): ColorTheme { +export function SecondaryStructureColorTheme(ctx: ThemeDataContext, props: SecondaryStructureColorThemeProps): ColorTheme<SecondaryStructureColorThemeProps> { function color(location: Location): Color { if (StructureElement.isLocation(location)) { return secondaryStructureColor(location.unit, location.element) @@ -72,12 +80,16 @@ export function SecondaryStructureColorTheme(props: ColorThemeProps): ColorTheme } return { - features: {}, granularity: 'group', color, + props, description: Description, legend: TableLegend(Object.keys(SecondaryStructureColors).map(name => { return [name, (SecondaryStructureColors as any)[name] as Color] as [string, Color] }).concat([[ 'Other', DefaultSecondaryStructureColor ]])) } +} + +export const SecondaryStructureColorThemeProvider: ColorTheme.Provider<typeof SecondaryStructureColorThemeParams> = { + factory: SecondaryStructureColorTheme, params: getSecondaryStructureColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/sequence-id.ts b/src/mol-theme/color/sequence-id.ts index 808e4ace55c17a952ee46d6dd8fc14f8c68dd8e5..a0b1b22d4a5b3d35661d67bbe3bb6dcf5db3f232 100644 --- a/src/mol-theme/color/sequence-id.ts +++ b/src/mol-theme/color/sequence-id.ts @@ -8,13 +8,22 @@ import { Unit, StructureElement, Link, ElementIndex } from 'mol-model/structure' import { ColorScale, Color } from 'mol-util/color'; import { Location } from 'mol-model/location'; -import { ColorThemeProps, ColorTheme } from '../color'; -import { ColorOther } from 'mol-util/color/tables'; -import { defaults } from 'mol-util'; +import { ColorTheme } from '../color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; +import { ColorListOptions, ColorListName } from 'mol-util/color/scale'; const DefaultColor = Color(0xCCCCCC) const Description = 'Gives every polymer residue a color based on its `seq_id` value.' +export const SequenceIdColorThemeParams = { + list: PD.Select<ColorListName>('Color Scale', '', 'rainbow', ColorListOptions), +} +export function getSequenceIdColorThemeParams(ctx: ThemeDataContext) { + return SequenceIdColorThemeParams // TODO return copy +} +export type SequenceIdColorThemeProps = PD.DefaultValues<typeof SequenceIdColorThemeParams> + function getSeqId(unit: Unit, element: ElementIndex): number { const { model } = unit switch (unit.kind) { @@ -55,15 +64,12 @@ function getSequenceLength(unit: Unit, element: ElementIndex) { return model.sequence.byEntityKey[entityIndex].sequence.sequence.length } -export function SequenceIdColorTheme(props: ColorThemeProps): ColorTheme { - const p = { - ...props, - list: defaults(props.list, ColorOther.rainbow), +export function SequenceIdColorTheme(ctx: ThemeDataContext, props: SequenceIdColorThemeProps): ColorTheme<SequenceIdColorThemeProps> { + const scale = ColorScale.create({ + listOrName: props.list, minLabel: 'Start', maxLabel: 'End', - } - - const scale = ColorScale.create(p) + }) const color = (location: Location): Color => { if (StructureElement.isLocation(location)) { const { unit, element } = location @@ -84,11 +90,14 @@ export function SequenceIdColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: { list: true }, granularity: 'group', color, + props, description: Description, - // legend: scale ? TableLegend(table) : undefined legend: scale ? scale.legend : undefined } +} + +export const SequenceIdColorThemeProvider: ColorTheme.Provider<typeof SequenceIdColorThemeParams> = { + factory: SequenceIdColorTheme, params: getSequenceIdColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/shape-group.ts b/src/mol-theme/color/shape-group.ts index 0d74a08c77afa0c23f265036e0279daf2c1d76b5..172052bd7e0037c4141e207ee614b7c1304f1da1 100644 --- a/src/mol-theme/color/shape-group.ts +++ b/src/mol-theme/color/shape-group.ts @@ -4,16 +4,24 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ColorTheme, ColorThemeProps } from '../color'; +import { ColorTheme } from '../color'; import { Color } from 'mol-util/color'; import { Location } from 'mol-model/location'; import { Shape } from 'mol-model/shape'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; const DefaultColor = Color(0xCCCCCC) +const Description = 'Assigns colors as defined by the shape object.' -export function ShapeGroupColorTheme(props: ColorThemeProps): ColorTheme { +export const ShapeGroupColorThemeParams = {} +export function getShapeGroupColorThemeParams(ctx: ThemeDataContext) { + return ShapeGroupColorThemeParams // TODO return copy +} +export type ShapeGroupColorThemeProps = PD.DefaultValues<typeof ShapeGroupColorThemeParams> + +export function ShapeGroupColorTheme(ctx: ThemeDataContext, props: ShapeGroupColorThemeProps): ColorTheme<ShapeGroupColorThemeProps> { return { - features: {}, granularity: 'group', color: (location: Location): Color => { if (Shape.isLocation(location)) { @@ -21,7 +29,11 @@ export function ShapeGroupColorTheme(props: ColorThemeProps): ColorTheme { } return DefaultColor }, - description: props.description, - legend: props.legend + props, + description: Description } +} + +export const ShapeGroupColorThemeProvider: ColorTheme.Provider<typeof ShapeGroupColorThemeParams> = { + factory: ShapeGroupColorTheme, params: getShapeGroupColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/uniform.ts b/src/mol-theme/color/uniform.ts index f7fb57769ecbdcfbdbe6a9ba6bda5507eedbd45f..c02644b3f2e9f209fa772a2c799fce408143b33b 100644 --- a/src/mol-theme/color/uniform.ts +++ b/src/mol-theme/color/uniform.ts @@ -4,20 +4,34 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ColorTheme, ColorThemeProps, TableLegend } from '../color'; +import { ColorTheme, TableLegend } from '../color'; import { Color } from 'mol-util/color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; const DefaultColor = Color(0xCCCCCC) const Description = 'Gives everything the same, uniform color.' -export function UniformColorTheme(props: ColorThemeProps): ColorTheme { +export const UniformColorThemeParams = { + value: PD.Color('Color Value', '', DefaultColor), +} +export function getUniformColorThemeParams(ctx: ThemeDataContext) { + return UniformColorThemeParams // TODO return copy +} +export type UniformColorThemeProps = PD.DefaultValues<typeof UniformColorThemeParams> + +export function UniformColorTheme(ctx: ThemeDataContext, props: UniformColorThemeProps): ColorTheme<UniformColorThemeProps> { const color = props.value || DefaultColor return { - features: {}, granularity: 'uniform', color: () => color, + props: props, description: Description, legend: TableLegend([['uniform', color]]) } +} + +export const UniformColorThemeProvider: ColorTheme.Provider<typeof UniformColorThemeParams> = { + factory: UniformColorTheme, params: getUniformColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/color/unit-index.ts b/src/mol-theme/color/unit-index.ts index a17dc82b6e40a5c7ac2782a970d248b682e0fd7b..06760c3120e24769b6f7acf0712d267b0d19bcd8 100644 --- a/src/mol-theme/color/unit-index.ts +++ b/src/mol-theme/color/unit-index.ts @@ -7,17 +7,28 @@ import { ColorScale, Color } from 'mol-util/color'; import { Location } from 'mol-model/location'; import { StructureElement, Link } from 'mol-model/structure'; -import { ColorTheme, ColorThemeProps, LocationColor } from '../color'; +import { ColorTheme, LocationColor } from '../color'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; +import { ColorListOptions, ColorListName } from 'mol-util/color/scale'; const DefaultColor = Color(0xCCCCCC) const Description = 'Gives every unit (single chain or collection of single elements) a unique color based on the position (index) of the unit in the list of units in the structure.' -export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme { +export const UnitIndexColorThemeParams = { + list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions), +} +export function getUnitIndexColorThemeParams(ctx: ThemeDataContext) { + return UnitIndexColorThemeParams // TODO return copy +} +export type UnitIndexColorThemeProps = PD.DefaultValues<typeof UnitIndexColorThemeParams> + +export function UnitIndexColorTheme(ctx: ThemeDataContext, props: UnitIndexColorThemeProps): ColorTheme<UnitIndexColorThemeProps> { let color: LocationColor - const scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' }) + const scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' }) - if (props.structure) { - const { units } = props.structure + if (ctx.structure) { + const { units } = ctx.structure scale.setDomain(0, units.length - 1) const unitIdColor = new Map<number, Color>() for (let i = 0, il = units.length; i <il; ++i) { @@ -37,10 +48,14 @@ export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme { } return { - features: { structure: true, list: true }, granularity: 'instance', color, + props, description: Description, legend: scale ? scale.legend : undefined } +} + +export const UnitIndexColorThemeProvider: ColorTheme.Provider<typeof UnitIndexColorThemeParams> = { + factory: UnitIndexColorTheme, params: getUnitIndexColorThemeParams } \ No newline at end of file diff --git a/src/mol-theme/size.ts b/src/mol-theme/size.ts index 65428f9d0ce22ffd84f4865a529cded363f4e083..55487c2663c3c311021a533ee82581ee32b6da92 100644 --- a/src/mol-theme/size.ts +++ b/src/mol-theme/size.ts @@ -4,35 +4,69 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Structure } from 'mol-model/structure'; import { SizeType, LocationSize } from 'mol-geo/geometry/size-data'; +import { UniformSizeTheme, UniformSizeThemeProvider } from './size/uniform'; +import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { ThemeDataContext } from 'mol-theme/theme'; +import { PhysicalSizeThemeProvider } from './size/physical'; +import { deepEqual } from 'mol-util'; -import { PhysicalSizeTheme } from './size/physical'; -import { UniformSizeTheme } from './size/uniform'; - -export interface SizeTheme { - granularity: SizeType - size: LocationSize +export { SizeTheme } +interface SizeTheme<P extends SizeTheme.Props = {}> { + readonly granularity: SizeType + readonly size: LocationSize + readonly props: Readonly<P> + readonly description?: string } +namespace SizeTheme { + export type Props = { [k: string]: any } + export const Empty = UniformSizeTheme({}, { value: 1 }) -export function SizeTheme(props: SizeThemeProps): SizeTheme { - switch (props.name) { - case 'physical': return PhysicalSizeTheme(props) - case 'uniform': return UniformSizeTheme(props) + export function areEqual(themeA: SizeTheme, themeB: SizeTheme) { + return themeA === themeB && deepEqual(themeA.props, themeB.props) } -} -export interface SizeThemeProps { - name: 'physical' | 'uniform' - value?: number - factor?: number - structure?: Structure + export interface Provider<P extends PD.Params> { + readonly factory: (ctx: ThemeDataContext, props: PD.DefaultValues<P>) => SizeTheme<PD.DefaultValues<P>> + readonly params: (ctx: ThemeDataContext) => P + } + + export class Registry { + private _list: { name: string, provider: Provider<any> }[] = [] + private _map = new Map<string, Provider<any>>() + + constructor() { + Object.keys(BuiltInSizeThemes).forEach(name => { + const p = (BuiltInSizeThemes as { [k: string]: Provider<any> })[name] + this.add(name, p.factory, p.params) + }) + } + + add<P extends PD.Params>(name: string, factory: Provider<P>['factory'], params: Provider<P>['params']) { + const provider = { factory, params } as Provider<P> + this._list.push({ name, provider }) + this._map.set(name, provider) + } + + get(id: string) { + return this._map.get(id) + } + + create(id: string, ctx: ThemeDataContext, props = {}) { + const provider = this.get(id) + return provider ? provider.factory(ctx, { ...PD.getDefaultValues(provider.params(ctx)), ...props }) : Empty + } + + get list() { + return this._list + } + } } -export const SizeThemeInfo = { - 'physical': {}, - 'uniform': {} +export const BuiltInSizeThemes = { + 'physical': PhysicalSizeThemeProvider, + 'uniform': UniformSizeThemeProvider } -export type SizeThemeName = keyof typeof SizeThemeInfo -export const SizeThemeNames = Object.keys(SizeThemeInfo) -export const SizeThemeOptions = SizeThemeNames.map(n => [n, n] as [SizeThemeName, string]) \ No newline at end of file +export type BuiltInSizeThemeName = keyof typeof BuiltInSizeThemes +export const BuiltInSizeThemeNames = Object.keys(BuiltInSizeThemes) +export const BuiltInSizeThemeOptions = BuiltInSizeThemeNames.map(n => [n, n] as [BuiltInSizeThemeName, string]) \ No newline at end of file diff --git a/src/mol-theme/size/physical.ts b/src/mol-theme/size/physical.ts index 43a885989c0faf14da2a57fbc8b3f02eabc2aede..45d43ceac6f8549e4f49c2c0db63854a047c0500 100644 --- a/src/mol-theme/size/physical.ts +++ b/src/mol-theme/size/physical.ts @@ -6,11 +6,19 @@ import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure'; import { Location } from 'mol-model/location'; -import { SizeThemeProps, SizeTheme } from '../size'; +import { SizeTheme } from '../size'; import { VdwRadius } from 'mol-model/structure/model/properties/atomic'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; const DefaultSize = 1 -const DefaultFactor = 1 +const Description = 'Assigns a physical size.' + +export const PhysicalSizeThemeParams = {} +export function getPhysicalSizeThemeParams(ctx: ThemeDataContext) { + return PhysicalSizeThemeParams // TODO return copy +} +export type PhysicalSizeThemeProps = PD.DefaultValues<typeof PhysicalSizeThemeParams> export function getPhysicalRadius(unit: Unit, element: ElementIndex): number { if (Unit.isAtomic(unit)) { @@ -26,10 +34,8 @@ export function getPhysicalRadius(unit: Unit, element: ElementIndex): number { * Create attribute data with the physical size of an element, * i.e. vdw for atoms and radius for coarse spheres */ -export function PhysicalSizeTheme(props: SizeThemeProps): SizeTheme { - const factor = props.factor || DefaultFactor - - function sizeFn(location: Location): number { +export function PhysicalSizeTheme(ctx: ThemeDataContext, props: PhysicalSizeThemeProps): SizeTheme<PhysicalSizeThemeProps> { + function size(location: Location): number { let size: number if (StructureElement.isLocation(location)) { size = getPhysicalRadius(location.unit, location.element) @@ -38,11 +44,17 @@ export function PhysicalSizeTheme(props: SizeThemeProps): SizeTheme { } else { size = DefaultSize } - return factor * size + return size } return { granularity: 'group', - size: sizeFn + size, + props, + description: Description } +} + +export const PhysicalSizeThemeProvider: SizeTheme.Provider<typeof PhysicalSizeThemeParams> = { + factory: PhysicalSizeTheme, params: getPhysicalSizeThemeParams } \ No newline at end of file diff --git a/src/mol-theme/size/uniform.ts b/src/mol-theme/size/uniform.ts index 28634f5ee67867bd55df0f95c95158cce5a27dbf..139a4bcbc3505fde6ef80ce5270234d868deafd1 100644 --- a/src/mol-theme/size/uniform.ts +++ b/src/mol-theme/size/uniform.ts @@ -4,18 +4,31 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { SizeTheme, SizeThemeProps } from '../size'; +import { SizeTheme } from '../size'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; -const DefaultSize = 1 -const DefaultFactor = 1 +const Description = 'Gives everything the same, uniform size.' -export function UniformSizeTheme(props: SizeThemeProps): SizeTheme { - const value = props.value || DefaultSize - const factor = props.factor || DefaultFactor - const size = value * factor +export const UniformSizeThemeParams = { + value: PD.Numeric('Size Value', '', 1, 0, 20, 0.1), +} +export function getUniformSizeThemeParams(ctx: ThemeDataContext) { + return UniformSizeThemeParams // TODO return copy +} +export type UniformSizeThemeProps = PD.DefaultValues<typeof UniformSizeThemeParams> + +export function UniformSizeTheme(ctx: ThemeDataContext, props: UniformSizeThemeProps): SizeTheme<UniformSizeThemeProps> { + const size = props.value return { granularity: 'uniform', - size: () => size + size: () => size, + props, + description: Description } +} + +export const UniformSizeThemeProvider: SizeTheme.Provider<typeof UniformSizeThemeParams> = { + factory: UniformSizeTheme, params: getUniformSizeThemeParams } \ No newline at end of file diff --git a/src/mol-theme/theme.ts b/src/mol-theme/theme.ts new file mode 100644 index 0000000000000000000000000000000000000000..a5f1a3e80e8ec39bd68a122ab4eee34a3f6a2c60 --- /dev/null +++ b/src/mol-theme/theme.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { ColorTheme } from './color'; +import { SizeTheme } from './size'; +import { Structure } from 'mol-model/structure'; +import { VolumeData } from 'mol-model/volume'; + +export interface ThemeRegistryContext { + colorThemeRegistry: ColorTheme.Registry + sizeThemeRegistry: SizeTheme.Registry +} + +export interface ThemeDataContext { + [k: string]: any + structure?: Structure + volume?: VolumeData +} + +export interface ThemeProps { color?: {}, size?: {} } + +export interface Theme { + color: ColorTheme + size: SizeTheme + // label: LabelTheme // TODO +} + +type Props = { [k: string]: any } + +export function createTheme(ctx: ThemeRegistryContext, data: ThemeDataContext, props: Props, themeProps: ThemeProps = {}, theme?: Theme) { + theme = theme || { + color: ColorTheme.Empty, + size: SizeTheme.Empty + } + // TODO check if props have changed + if (typeof props.colorTheme === 'string') { + theme.color = ctx.colorThemeRegistry.create(props.colorTheme, data, themeProps.color) + } + if (typeof props.sizeTheme === 'string') { + theme.size = ctx.sizeThemeRegistry.create(props.sizeTheme, data, themeProps.size) + } + return theme +} \ No newline at end of file diff --git a/src/mol-util/color/scale.ts b/src/mol-util/color/scale.ts index c7cf7980c114e7b5363ede0cc7b80a1b176c0f5e..7ed018496fcfdd4666f29f77325fe9f20fa92047 100644 --- a/src/mol-util/color/scale.ts +++ b/src/mol-util/color/scale.ts @@ -5,10 +5,32 @@ */ import { Color } from './color' -import { ColorBrewer } from './tables' +import { ColorBrewer, ColorMatplotlib, ColorOther } from './tables' import { ScaleLegend } from 'mol-theme/color'; import { defaults } from 'mol-util'; +export type ColorListName = ( + keyof typeof ColorBrewer | keyof typeof ColorMatplotlib | keyof typeof ColorOther +) +export const ColorListNames = [ + ...Object.keys(ColorBrewer), ...Object.keys(ColorMatplotlib), ...Object.keys(ColorOther) +] +export const ColorListOptions = ColorListNames.map(n => [n, n] as [ColorListName, string]) + +export function getColorListFromName(name: ColorListName) { + if (name in ColorBrewer) { + return ColorBrewer[name as keyof typeof ColorBrewer] + } else if (name in ColorMatplotlib) { + return ColorMatplotlib[name as keyof typeof ColorMatplotlib] + } else if (name in ColorOther) { + return ColorOther[name as keyof typeof ColorOther] + } + console.warn(`unknown color list named '${name}'`) + return ColorBrewer.RdYlBu +} + +// + export interface ColorScale { /** Returns hex color for given value */ color: (value: number) => Color @@ -22,20 +44,20 @@ export interface ColorScale { readonly legend: ScaleLegend } -export const DefaultColorScale = { +export const DefaultColorScaleProps = { domain: [0, 1], reverse: false, - list: ColorBrewer.RdYlBu, + listOrName: ColorBrewer.RdYlBu as Color[] | ColorListName, minLabel: '' as string | undefined, maxLabel: '' as string | undefined, } -export type ColorScaleProps = Partial<typeof DefaultColorScale> +export type ColorScaleProps = Partial<typeof DefaultColorScaleProps> export namespace ColorScale { export function create(props: ColorScaleProps): ColorScale { - // ensure that no undefined .list property exists so that the default assignment works - if (props.list === undefined) delete props.list - const { domain, reverse, list } = { ...DefaultColorScale, ...props } + const { domain, reverse, listOrName } = { ...DefaultColorScaleProps, ...props } + const list = typeof listOrName === 'string' ? getColorListFromName(listOrName) : listOrName + const colors = reverse ? list.slice().reverse() : list const count1 = colors.length - 1 diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index 0ebf49dd83c29c74133912ff304a2ec92ec1128f..2b7804bc7a4fbbf6f6780749ceb55f5d2cf8649a 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -82,12 +82,20 @@ export namespace ParamDefinition { return { type: 'number', label, description, defaultValue, min, max, step } } - export type Any = /* ValueParam<any> | */ Select<any> | MultiSelect<any> | Boolean | Range | Text | Color | Numeric + export interface Interval extends Base<[number, number]> { + type: 'interval' + } + export function Interval(label: string, description: string, defaultValue: [number, number]): Interval { + return { type: 'interval', label, description, defaultValue } + } + + export type Any = /* GenericValue<any> | */ Select<any> | MultiSelect<any> | Boolean | Range | Text | Color | Numeric | Interval export type Params = { [k: string]: Any } + export type DefaultValues<T extends Params> = { [k in keyof T]: T[k]['defaultValue'] } export function getDefaultValues<T extends Params>(params: T) { const d: { [k: string]: any } = {} Object.keys(params).forEach(k => d[k] = params[k].defaultValue) - return d as { [k in keyof T]: T[k]['defaultValue'] } + return d as DefaultValues<T> } } \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index b1aba103a11afae350c6929a901a92b15f0a37a7..0f85d141c04135fc627cc8855fcab338f179ef88 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,7 @@ const path = require('path'); const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin'); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +// const CircularDependencyPlugin = require('circular-dependency-plugin'); module.exports = { module: { rules: [ @@ -30,6 +31,11 @@ module.exports = { ] }, plugins: [ + // new CircularDependencyPlugin({ + // include: [ path.resolve(__dirname, 'build/node_modules/') ], + // failOnError: false, + // cwd: process.cwd(), + // }), new ExtraWatchWebpackPlugin({ files: [ './build/node_modules/**/*.vert',