src/app/features/organ/organ.component.ts
AfterViewChecked
OnChanges
changeDetection | ChangeDetectionStrategy.OnPush |
selector | ccf-organ |
styleUrls | ./organ.component.scss |
templateUrl | ./organ.component.html |
Properties |
|
Methods |
Inputs |
Outputs |
constructor(ga: GoogleAnalyticsService)
|
||||||
Defined in src/app/features/organ/organ.component.ts:39
|
||||||
Parameters :
|
blocks | |
Type : TissueBlockResult[]
|
|
Defined in src/app/features/organ/organ.component.ts:29
|
filter | |
Type : Filter
|
|
Defined in src/app/features/organ/organ.component.ts:30
|
organ | |
Type : SpatialEntity
|
|
Defined in src/app/features/organ/organ.component.ts:24
|
organIri | |
Type : string
|
|
Defined in src/app/features/organ/organ.component.ts:26
|
scene | |
Type : SpatialSceneNode[]
|
|
Defined in src/app/features/organ/organ.component.ts:25
|
sex | |
Type : "Male" | "Female" | "Both"
|
|
Defined in src/app/features/organ/organ.component.ts:27
|
side | |
Type : "Left" | "Right"
|
|
Defined in src/app/features/organ/organ.component.ts:28
|
nodeClick | |
Type : EventEmitter
|
|
Defined in src/app/features/organ/organ.component.ts:34
|
sexChange | |
Type : EventEmitter
|
|
Defined in src/app/features/organ/organ.component.ts:32
|
sideChange | |
Type : EventEmitter
|
|
Defined in src/app/features/organ/organ.component.ts:33
|
nodeClicked | ||||||
nodeClicked(event: NodeClickEvent)
|
||||||
Defined in src/app/features/organ/organ.component.ts:90
|
||||||
Parameters :
Returns :
void
|
updateHighlighting |
updateHighlighting()
|
Defined in src/app/features/organ/organ.component.ts:47
|
Returns :
void
|
updateSex | ||||||
updateSex(selection?: "Male" | "Female")
|
||||||
Defined in src/app/features/organ/organ.component.ts:70
|
||||||
Parameters :
Returns :
void
|
updateSide | ||||||
updateSide(selection?: "Left" | "Right")
|
||||||
Defined in src/app/features/organ/organ.component.ts:75
|
||||||
Parameters :
Returns :
void
|
zoomToFitOrgan |
zoomToFitOrgan()
|
Defined in src/app/features/organ/organ.component.ts:80
|
Returns :
void
|
Readonly bodyUI |
Type : BodyUiComponent
|
Decorators :
@ViewChild('bodyUI', {static: true})
|
Defined in src/app/features/organ/organ.component.ts:36
|
filteredBlocks |
Type : string[]
|
Defined in src/app/features/organ/organ.component.ts:39
|
highlightedNodeId |
Type : string
|
Defined in src/app/features/organ/organ.component.ts:38
|
import {
AfterViewChecked,
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
OnChanges,
Output,
SimpleChanges,
ViewChild,
} from '@angular/core';
import { NodeClickEvent, SpatialSceneNode } from 'ccf-body-ui';
import { Filter, SpatialEntity, TissueBlockResult } from 'ccf-database';
import { BodyUiComponent } from 'ccf-shared';
import { GoogleAnalyticsService } from 'ngx-google-analytics';
@Component({
selector: 'ccf-organ',
templateUrl: './organ.component.html',
styleUrls: ['./organ.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class OrganComponent implements AfterViewChecked, OnChanges {
@Input() organ?: SpatialEntity;
@Input() scene!: SpatialSceneNode[];
@Input() organIri!: string;
@Input() sex?: 'Male' | 'Female' | 'Both';
@Input() side?: 'Left' | 'Right';
@Input() blocks?: TissueBlockResult[];
@Input() filter?: Filter;
@Output() readonly sexChange = new EventEmitter<'Male' | 'Female'>();
@Output() readonly sideChange = new EventEmitter<'Left' | 'Right'>();
@Output() readonly nodeClick = new EventEmitter();
@ViewChild('bodyUI', { static: true }) readonly bodyUI!: BodyUiComponent;
highlightedNodeId!: string;
filteredBlocks!: string[];
constructor(readonly ga: GoogleAnalyticsService) {}
ngAfterViewChecked(): void {
this.updateHighlighting();
}
updateHighlighting(): void {
const providerName = new Set<string>(this.filter?.tmc ?? []);
this.filteredBlocks =
this.blocks?.filter((block) => providerName.has(block.donor.providerName)).map((block) => block['@id']) ?? [];
this.bodyUI.scene = this.bodyUI.scene.map(
(node): SpatialSceneNode => ({
...node,
color:
node.entityId && this.highlightedNodeId === node['@id']
? [30, 136, 229, 255]
: this.filteredBlocks.includes(node.entityId ?? '')
? [173, 255, 47, 229.5]
: [255, 255, 255, 229.5],
}),
);
}
ngOnChanges(changes: SimpleChanges): void {
if (this.bodyUI && 'organ' in changes) {
this.zoomToFitOrgan();
}
}
updateSex(selection?: 'Male' | 'Female'): void {
this.sex = selection;
this.sexChange.emit(this.sex);
}
updateSide(selection?: 'Left' | 'Right'): void {
this.side = selection;
this.sideChange.emit(this.side);
}
zoomToFitOrgan(): void {
const { bodyUI, organ } = this;
if (organ) {
const { x_dimension: x, y_dimension: y, z_dimension: z } = organ;
bodyUI.rotation = bodyUI.rotationX = 0;
bodyUI.bounds = { x: (1.25 * x) / 1000, y: (1.25 * y) / 1000, z: (1.25 * z) / 1000 };
bodyUI.target = [x / 1000 / 2, y / 1000 / 2, z / 1000 / 2];
}
}
nodeClicked(event: NodeClickEvent): void {
this.ga.event('node_click', 'organ', event.node['@id']);
this.highlightedNodeId =
this.highlightedNodeId && this.highlightedNodeId === event.node['@id'] ? '' : event.node['@id'];
this.nodeClick.emit(event);
}
}
<ccf-body-ui
#bodyUI
class="body-ui"
[scene]="scene"
[interactive]="true"
camera="perspective"
(nodeClick)="nodeClicked($event)"
(initialized)="zoomToFitOrgan()"
>
</ccf-body-ui>
<div class="stage-options">
<ccf-slide-toggle
class="view-slider"
[labels]="['Male', 'Female']"
[value]="sex!"
[hidden]="!sex"
(valueChange)="updateSex($any($event))"
>
</ccf-slide-toggle>
<ccf-slide-toggle
class="view-slider"
[labels]="['Left', 'Right']"
[value]="side!"
[hidden]="!side"
(valueChange)="updateSide($any($event))"
>
</ccf-slide-toggle>
</div>
./organ.component.scss
:host {
display: block;
background-color: black;
border-radius: 0.5rem;
color: white;
height: 100%;
.body-ui {
height: 90%;
}
.stage-options {
padding: 1rem;
min-width: 352px;
}
}