Newer
Older
import React from 'react';
import ReactDOM from 'react-dom';
import { ReDNATCOMspApi as Api } from './api';
import { ReDNATCOMspApiImpl } from './api-impl';
import { DensityMapControls } from './density-map-controls';
import { NtCColors } from './colors';
import { ColorPicker } from './color-picker';
import { ColorBox, IconButton, PushButton, ToggleButton } from './controls';
import { ToolBar, ToolBarContent } from './tool-bar';
import { Color } from '../../mol-util/color';
import { assertUnreachable } from '../../mol-util/type-helpers';
import './assets/imgs/density-wireframe.svg';
import './assets/imgs/nucleic.svg';
import './assets/imgs/palette.svg';
import './assets/imgs/pyramid.svg';
const ConformersByClass = {
A: ['AA00_Upr', 'AA00_Lwr', 'AA02_Upr', 'AA02_Lwr', 'AA03_Upr', 'AA03_Lwr', 'AA04_Upr', 'AA04_Lwr', 'AA08_Upr', 'AA08_Lwr', 'AA09_Upr', 'AA09_Lwr', 'AA01_Upr', 'AA01_Lwr', 'AA05_Upr', 'AA05_Lwr', 'AA06_Upr', 'AA06_Lwr', 'AA10_Upr', 'AA10_Lwr', 'AA11_Upr', 'AA11_Lwr', 'AA07_Upr', 'AA07_Lwr', 'AA12_Upr', 'AA12_Lwr', 'AA13_Upr', 'AA13_Lwr', 'AB01_Upr', 'AB02_Upr', 'AB03_Upr', 'AB04_Upr', 'AB05_Upr', 'BA01_Lwr', 'BA05_Lwr', 'BA09_Lwr', 'BA08_Lwr', 'BA10_Lwr', 'BA13_Lwr', 'BA16_Lwr', 'BA17_Lwr', 'AAS1_Lwr', 'AB1S_Upr'],
B: ['AB01_Lwr', 'AB02_Lwr', 'AB03_Lwr', 'AB04_Lwr', 'AB05_Lwr', 'BA09_Upr', 'BA10_Upr', 'BB00_Upr', 'BB00_Lwr', 'BB01_Upr', 'BB01_Lwr', 'BB17_Upr', 'BB17_Lwr', 'BB02_Upr', 'BB02_Lwr', 'BB03_Upr', 'BB03_Lwr', 'BB11_Upr', 'BB11_Lwr', 'BB16_Upr', 'BB16_Lwr', 'BB04_Upr', 'BB05_Upr', 'BB1S_Upr', 'BB2S_Upr', 'BBS1_Lwr'],
BII: ['BA08_Upr', 'BA13_Upr', 'BA16_Upr', 'BA17_Upr', 'BB04_Lwr', 'BB05_Lwr', 'BB07_Upr', 'BB07_Lwr', 'BB08_Upr', 'BB08_Lwr'],
miB: ['BB10_Upr', 'BB10_Lwr', 'BB12_Upr', 'BB12_Lwr', 'BB13_Upr', 'BB13_Lwr', 'BB14_Upr', 'BB14_Lwr', 'BB15_Upr', 'BB15_Lwr', 'BB20_Upr', 'BB20_Lwr'],
IC: ['IC01_Upr', 'IC01_Lwr', 'IC02_Upr', 'IC02_Lwr', 'IC03_Upr', 'IC03_Lwr', 'IC04_Upr', 'IC04_Lwr', 'IC05_Upr', 'IC05_Lwr', 'IC06_Upr', 'IC06_Lwr', 'IC07_Upr', 'IC07_Lwr'],
OPN: ['OP01_Upr', 'OP01_Lwr', 'OP02_Upr', 'OP02_Lwr', 'OP03_Upr', 'OP03_Lwr', 'OP04_Upr', 'OP04_Lwr', 'OP05_Upr', 'OP05_Lwr', 'OP06_Upr', 'OP06_Lwr', 'OP07_Upr', 'OP07_Lwr', 'OP08_Upr', 'OP08_Lwr', 'OP09_Upr', 'OP09_Lwr', 'OP10_Upr', 'OP10_Lwr', 'OP11_Upr', 'OP11_Lwr', 'OP12_Upr', 'OP12_Lwr', 'OP13_Upr', 'OP13_Lwr', 'OP14_Upr', 'OP14_Lwr', 'OP15_Upr', 'OP15_Lwr', 'OP16_Upr', 'OP16_Lwr', 'OP17_Upr', 'OP17_Lwr', 'OP18_Upr', 'OP18_Lwr', 'OP19_Upr', 'OP19_Lwr', 'OP20_Upr', 'OP20_Lwr', 'OP21_Upr', 'OP21_Lwr', 'OP22_Upr', 'OP22_Lwr', 'OP23_Upr', 'OP23_Lwr', 'OP24_Upr', 'OP24_Lwr', 'OP25_Upr', 'OP25_Lwr', 'OP26_Upr', 'OP26_Lwr', 'OP27_Upr', 'OP27_Lwr', 'OP28_Upr', 'OP28_Lwr', 'OP29_Upr', 'OP29_Lwr', 'OP30_Upr', 'OP30_Lwr', 'OP31_Upr', 'OP31_Lwr', 'OPS1_Upr', 'OPS1_Lwr', 'OP1S_Upr', 'OP1S_Lwr'],
SYN: ['AAS1_Upr', 'AB1S_Lwr', 'AB2S_Lwr', 'BB1S_Lwr', 'BB2S_Lwr', 'BBS1_Upr', 'ZZ1S_Lwr', 'ZZ2S_Lwr', 'ZZS1_Upr', 'ZZS2_Upr'],
Z: ['ZZ01_Upr', 'ZZ01_Lwr', 'ZZ02_Upr', 'ZZ02_Lwr', 'ZZ1S_Upr', 'ZZ2S_Upr', 'ZZS1_Lwr', 'ZZS2_Lwr'],
N: ['NANT_Upr', 'NANT_Lwr'],
};
type ConformersByClass = typeof ConformersByClass;
type ToolBarItems = 'structure' | 'ntc' | 'colors' | 'density-maps';
const ViewerToolBar = ToolBar.Specialize<ToolBarItems>();
export type VisualRepresentations = 'ball-and-stick' | 'cartoon' | 'ntc-tube';
export type DensityMapRepresentation = 'wireframe' | 'solid';
export const DefaultDensityDifferencePositiveColor = Color(0x00C300);
export const DefaultDensityDifferenceNegativeColor = Color(0xC30000);
export const DefaultDensityMapColor = Color(0x009DFF);
const DefaultDensityMapDisplay = {
kind: '2fo-fc' as Api.DensityMapKind,
representations: [] as DensityMapRepresentation[],
isoValue: 0,
alpha: DefaultDensityMapAlpha,
colors: [{ color: DefaultDensityMapColor, name: 'Color' }],
};
export type DensityMapDisplay = typeof DefaultDensityMapDisplay;
nucleicRepresentation: 'cartoon' as VisualRepresentations,
proteinRepresentation: 'cartoon' as Omit<VisualRepresentations, 'ntc-tube'>,
showPyramids: true,
pyramidsTransparent: false,
classColors: { ...NtCColors.Classes },
conformerColors: { ...NtCColors.Conformers },
chainColor: DefaultChainColor,
waterColor: DefaultWaterColor,
},
export class ReDNATCOMsp extends React.Component<ReDNATCOMsp.Props, State> {
private currentFilter: Filters.All = Filters.Empty();
private viewer: ReDNATCOMspViewer | undefined = undefined;
private selectedStep: Api.Payloads.StepSelection | undefined = undefined;
constructor(props: ReDNATCOMsp.Props) {
super(props);
this.state = {
display: { ...Display },
showControls: false,
};
}
private classColorToConformers(k: keyof ConformersByClass, color: Color) {
const updated: Partial<NtCColors.Conformers> = {};
ConformersByClass[k].map(cfmr => updated[cfmr as keyof NtCColors.Conformers] = color);
return updated;
}
private finalizeNtCColorUpdate(display: Display) {
this.viewer!.changeNtCColors(display).then(() => {
if (display.structures.showNucleic && display.structures.nucleicRepresentation === 'ntc-tube') {
this.viewer!.changeChainColor(['nucleic'], display).then(() => {
this.setState({ ...this.state, display });
});
} else
this.setState({ ...this.state, display });
});
}
private updateChainColor(color: number) {
const display: Display = {
...this.state.display,
structures: {
...this.state.display.structures,
chainColor: Color(color),
},
this.viewer!.changeChainColor(['nucleic', 'protein'], display);
this.setState({ ...this.state, display });
}
private updateClassColor(changes: { cls: keyof NtCColors.Classes, color: number } | { cls: keyof NtCColors.Classes, color: number }[]) {
const classColors = { ...this.state.display.structures.classColors };
const isArray = Array.isArray(changes);
if (isArray) {
changes.forEach(item => classColors[item.cls] = Color(item.color));
} else
classColors[changes.cls] = Color(changes.color);
const conformerColors: NtCColors.Conformers = {
...this.state.display.structures.conformerColors,
...(isArray
? changes.map(item => this.classColorToConformers(item.cls, Color(item.color)))
: this.classColorToConformers(changes.cls, Color(changes.color)))
const display = { ...this.state.display };
display.structures.classColors = classColors;
display.structures.conformerColors = conformerColors;
this.finalizeNtCColorUpdate(display);
private updateConformerColor(changes: { conformer: keyof NtCColors.Conformers, color: number } | { conformer: keyof NtCColors.Conformers, color: number }[]) {
const conformerColors = { ...this.state.display.structures.conformerColors };
if (Array.isArray(changes))
changes.forEach(item => conformerColors[item.conformer] = Color(item.color));
else
conformerColors[changes.conformer] = Color(changes.color);
const display = { ...this.state.display };
display.structures.conformerColors = conformerColors;
this.finalizeNtCColorUpdate(display);
private updateWaterColor(color: number) {
const display: Display = {
...this.state.display,
structures: {
...this.state.display.structures,
waterColor: Color(color),
},
};
this.viewer!.changeWaterColor(display);
this.setState({ ...this.state, display });
}
if (type === 'current-filter') {
return Api.Queries.CurrentFilter(this.currentFilter);
} else if (type === 'current-model-number') {
return Api.Queries.CurrentModelNumber(this.viewer!.currentModelNumber());
return this.selectedStep ? Api.Queries.SelectedStep(this.selectedStep) : Api.Queries.SelectedStep();
for (const p in cmd) {
console.log(`${p}: ${cmd[p as keyof typeof cmd]}`);
}
if (cmd.type === 'redraw')
window.dispatchEvent(new Event('resize'));
else if (cmd.type === 'deselect-step') {
await this.viewer.actionDeselectStep(this.state.display);
} else if (cmd.type === 'filter') {
const ret = await this.viewer.actionApplyFilter(cmd.filter);
if (!ret) {
ReDNATCOMspApi.event(Api.Events.FilterFailed(''));
return;
}
this.currentFilter = cmd.filter;
ReDNATCOMspApi.event(Api.Events.FilterApplied());
const success = await this.viewer.actionSelectStep(cmd.step, cmd.prev, cmd.next, this.state.display);
if (!success) {
ReDNATCOMspApi.event(Api.Events.StepSelectedFail());
return;
}
ReDNATCOMspApi.event(Api.Events.StepSelectedOk(this.selectedStep.name));
} else if (cmd.type === 'switch-model') {
if (cmd.model < 1 || cmd.model > this.viewer.getModelCount())
return;
const display: Display = {
...this.state.display,
structures: {
...this.state.display.structures,
modelNumber: cmd.model,
},
this.viewer.switchModel(display.structures.modelNumber);
this.setState({ ...this.state, display });
}
}
loadStructure(coords: { data: string, type: Api.CoordinatesFormat }, densityMaps: { data: Uint8Array, type: Api.DensityMapFormat, kind: Api.DensityMapKind }[] | null) {
const display = { ...this.state.display };
if (densityMaps) {
display.densityMaps.length = densityMaps.length;
for (let idx = 0; idx < densityMaps.length; idx++) {
const dm = densityMaps[idx];
if (dm.kind === 'fo-fc') {
display.densityMaps[idx] = {
...DefaultDensityMapDisplay,
kind: dm.kind,
colors: [
{ color: DefaultDensityDifferencePositiveColor, name: '+' },
{ color: DefaultDensityDifferenceNegativeColor, name: '-' },
],
};
} else
display.densityMaps[idx] = { ...DefaultDensityMapDisplay, kind: dm.kind };
}
} else
display.densityMaps.length = 0;
this.viewer.loadStructure(coords, densityMaps, display).then(() => {
this.presentConformers = this.viewer!.getPresentConformers();
ReDNATCOMspApi.event(Api.Events.StructureLoaded());
this.viewer!.actionDeselectStep(this.state.display);
ReDNATCOMspApi.event(Api.Events.StepDeselected());
}
viewerStepSelected(stepName: string) {
ReDNATCOMspApi.event(Api.Events.StepRequested(stepName));
}
componentDidMount() {
if (!this.viewer) {
const elem = document.getElementById(this.props.elemId + '-viewer');
ReDNATCOMspViewer.create(elem!, this).then(viewer => {
this.viewer.loadReferenceConformers().then(() => {
});
}
}
render() {
const ready = this.viewer?.isReady() ?? false;
const hasNucleic = this.viewer?.has('structure', 'nucleic') ?? false;
const hasProtein = this.viewer?.has('structure', 'protein') ?? false;
const hasWater = this.viewer?.has('structure', 'water') ?? false;
return (
<div className='rmsp-app'>
<div style={{ display: 'flex', flexDirection: 'row', height: '100%' }}>
<ViewerToolBar
orientation='vertical'
onBlockChanged={() => this.viewer?.redraw()}
controlBlocks={[
{
id: 'structure',
icon: './imgs/nucleic.svg',
content:
<ToolBarContent style={{ width: '10em' }}>
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<ToggleButton
text='Nucleic'
enabled={hasNucleic}
switchedOn={this.state.display.structures.showNucleic}
onClicked={() => {
const display = { ...this.state.display };
display.structures.showNucleic = !display.structures.showNucleic,
this.viewer!.toggleSubstructure('nucleic', display).then(() => {
this.setState({ ...this.state, display });
});
}}
/>
</div>
</div>
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<PushButton
text='Cartoon'
enabled={ready && this.state.display.structures.showNucleic}
onClicked={() => {
const display = { ...this.state.display };
if (display.structures.nucleicRepresentation !== 'cartoon') {
display.structures.nucleicRepresentation = 'cartoon';
this.viewer!.changeRepresentation('nucleic', display).then(() => {
this.setState({ ...this.state, display });
});
}
}}
/>
</div>
</div>
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<PushButton
text='Ball-and-stick'
enabled={ready && this.state.display.structures.showNucleic}
onClicked={() => {
const display = { ...this.state.display };
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
if (display.structures.nucleicRepresentation !== 'ball-and-stick') {
display.structures.nucleicRepresentation = 'ball-and-stick';
this.viewer!.changeRepresentation('nucleic', display).then(() => {
this.setState({ ...this.state, display });
});
}
}}
/>
</div>
</div>
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<PushButton
text='NtC tube'
enabled={ready && this.state.display.structures.showNucleic}
onClicked={() => {
const display = { ...this.state.display };
if (display.structures.nucleicRepresentation !== 'ntc-tube') {
display.structures.nucleicRepresentation = 'ntc-tube';
this.viewer!.changeRepresentation('nucleic', display).then(() => {
display.structures.showPyramids = false;
this.viewer!.changePyramids(display).then(() => {
this.setState({ ...this.state, display });
});
});
}
<div className='rmsp-control-vertical-spacer' />
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<ToggleButton
text='Protein'
enabled={hasProtein}
switchedOn={this.state.display.structures.showProtein}
onClicked={() => {
const display = { ...this.state.display };
display.structures.showProtein = !display.structures.showProtein,
this.viewer!.toggleSubstructure('protein', display).then(() => {
this.setState({ ...this.state, display });
});
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<PushButton
text='Cartoon'
enabled={ready && this.state.display.structures.showProtein}
onClicked={() => {
const display = { ...this.state.display };
if (display.structures.proteinRepresentation !== 'cartoon') {
display.structures.proteinRepresentation = 'cartoon';
this.viewer!.changeRepresentation('protein', display).then(() => {
this.setState({ ...this.state, display });
});
}
}}
/>
</div>
</div>
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<PushButton
text='Ball-and-stick'
enabled={ready && this.state.display.structures.showProtein}
onClicked={() => {
const display = { ...this.state.display };
if (display.structures.proteinRepresentation !== 'ball-and-stick') {
display.structures.proteinRepresentation = 'ball-and-stick';
this.viewer!.changeRepresentation('protein', display).then(() => {
this.setState({ ...this.state, display });
});
}
}}
/>
</div>
</div>
<div className='rmsp-control-vertical-spacer' />
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<ToggleButton
text='Water'
enabled={hasWater}
switchedOn={this.state.display.structures.showWater}
onClicked={() => {
const display = { ...this.state.display };
display.structures.showWater = !this.state.display.structures.showWater;
this.viewer!.toggleSubstructure('water', display).then(() => {
this.setState({ ...this.state, display });
});
}}
/>
</div>
</div>
</ToolBarContent>
},
{
id: 'ntc',
icon: './imgs/pyramid.svg',
content:
<ToolBarContent style={{ width: '10em' }}>
<div className='rmsp-control-vertical-section-caption'>
Pyramids
</div>
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<ToggleButton
text={this.state.display.structures.showPyramids ? 'Shown' : 'Hidden'}
enabled={ready}
switchedOn={this.state.display.structures.showPyramids}
onClicked={() => {
const display = { ...this.state.display };
display.structures.showPyramids = !display.structures.showPyramids;
this.viewer!.changePyramids(display).then(() => {
this.setState({ ...this.state, display });
});
}}
/>
</div>
</div>
<div className='rmsp-control-line'>
<div className='rmsp-control-item'>
<PushButton
text={this.state.display.structures.pyramidsTransparent ? 'Transp.' : 'Solid'}
enabled={this.state.display.structures.showPyramids}
onClicked={() => {
const display = { ...this.state.display };
display.structures.pyramidsTransparent = !display.structures.pyramidsTransparent;
this.viewer!.changePyramids(display).then(() => {
this.setState({ ...this.state, display });
});
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
}}
/>
</div>
</div>
</ToolBarContent>
},
{
id: 'colors',
icon: './imgs/palette.svg',
content:
<ToolBarContent>
<div className='rmsp-control-vertical-section-caption'>
NtC classes
</div>
{(['A', 'B', 'BII', 'miB', 'Z', 'IC', 'OPN', 'SYN', 'N'] as (keyof NtCColors.Classes)[]).map(k =>
<div className='rmsp-control-line' key={k}>
<div className='rmsp-control-item-group'>
<div
className='rmsp-control-item'
onClick={evt => ColorPicker.create(
evt,
this.state.display.structures.classColors[k],
color => this.updateClassColor({ cls: k, color })
)}
>
<ColorBox caption={k} color={this.state.display.structures.classColors[k]} />
</div>
<div className='rmsp-control-horitontal-spacer'>{'\u00A0'}</div>
<IconButton
img='imgs/reload.svg'
onClicked={() => this.updateClassColor({ cls: k, color: NtCColors.Classes[k] })}
enabled={true}
/>
</div>
</div>
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
<div className='rmsp-control-vertical-spacer' />
<div className='rmsp-control-vertical-section-caption'>
Conformers
</div>
{this.presentConformers.map(ntc => {
const uprKey = ntc + '_Upr' as keyof NtCColors.Conformers;
const lwrKey = ntc + '_Lwr' as keyof NtCColors.Conformers;
return (
<div className='rmsp-control-line' key={ntc}>
<div className='rmsp-control-item-group'>
<div
className='rmsp-control-item'
onClick={evt => ColorPicker.create(
evt,
this.state.display.structures.conformerColors[uprKey],
color => this.updateConformerColor({ conformer: uprKey, color })
)}
>
<ColorBox caption={`${ntc.slice(0, 2)}`} color={this.state.display.structures.conformerColors[uprKey]} />
</div>
<div
className='rmsp-control-item'
onClick={evt => ColorPicker.create(
evt,
this.state.display.structures.conformerColors[lwrKey],
color => this.updateConformerColor({ conformer: lwrKey, color })
)}
>
<ColorBox caption={`${ntc.slice(2)}`} color={this.state.display.structures.conformerColors[lwrKey]} />
</div>
<div className='rmsp-control-horitontal-spacer'>{'\u00A0'}</div>
<IconButton
img='imgs/reload.svg'
onClicked={() => {
this.updateConformerColor([
{ conformer: uprKey, color: NtCColors.Conformers[uprKey] },
{ conformer: lwrKey, color: NtCColors.Conformers[lwrKey] }
]);
}}
enabled={true}
/>
</div>
</div>
);
})}
<div className='rmsp-control-vertical-spacer' />
<div className='rmsp-control-vertical-section-caption'>
Structure
</div>
<div className='rmsp-control-line'>
<div className='rmsp-control-item-group'>
<div
className='rmsp-control-item'
onClick={evt => ColorPicker.create(
evt,
this.state.display.structures.chainColor,
color => this.updateChainColor(color)
)}
>
<ColorBox caption='Chains' color={this.state.display.structures.chainColor} />
</div>
<div className='rmsp-control-horitontal-spacer'>{'\u00A0'}</div>
<IconButton
img='imgs/reload.svg'
onClicked={() => this.updateChainColor(DefaultChainColor)}
enabled={true}
/>
</div>
<div className='rmsp-control-line'>
<div className='rmsp-control-item-group'>
<div
className='rmsp-control-item'
onClick={evt => ColorPicker.create(
evt,
this.state.display.structures.waterColor,
color => this.updateWaterColor(color)
)}
>
<ColorBox caption='Waters' color={this.state.display.structures.waterColor} />
</div>
<div className='rmsp-control-horitontal-spacer'>{'\u00A0'}</div>
<IconButton
img='imgs/reload.svg'
onClicked={() => this.updateChainColor(DefaultWaterColor)}
enabled={true}
/>
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
</ToolBarContent>
},
{
id: 'density-maps',
icon: './imgs/density-wireframe.svg',
content:
<ToolBarContent>
<DensityMapControls
viewer={this.viewer!}
display={this.state.display.densityMaps}
toggleWireframe={(index) => {
const display = { ...this.state.display };
display.densityMaps[index].representations = toggleArray(display.densityMaps[index].representations, 'wireframe');
this.viewer!.changeDensityMap(index, display);
this.setState({ ...this.state, display });
}}
toggleSolid={(index) => {
const display = { ...this.state.display };
display.densityMaps[index].representations = toggleArray(display.densityMaps[index].representations, 'solid');
this.viewer!.changeDensityMap(index, display);
this.setState({ ...this.state, display });
}}
changeIso={(index, v) => {
const display = { ...this.state.display };
display.densityMaps[index].isoValue = v;
this.viewer!.changeDensityMap(index, display);
this.setState({ ...this.state, display });
}}
changeAlpha={(index, alpha) => {
const display = { ...this.state.display };
display.densityMaps[index].alpha = alpha;
this.viewer!.changeDensityMap(index, display);
this.setState({ ...this.state, display });
}}
changeColors={(index, colors) => {
const display = { ...this.state.display };
display.densityMaps[index].colors = colors;
this.viewer!.changeDensityMap(index, display);
this.setState({ ...this.state, display });
}}
/>
</ToolBarContent>,
disabled: !this.viewer?.hasDensityMaps()
}
]}
<div id={this.props.elemId + '-viewer'} className='rmsp-viewer'></div>
</div>
export interface Props {
elemId: string;
}
const elem = document.getElementById(elemId);
if (!elem)
throw new Error(`Element ${elemId} does not exist`);
ReactDOM.render(<ReDNATCOMsp elemId={elemId} />, elem);
export const ReDNATCOMspApi = new ReDNATCOMspApiImpl();