From 2f6f159bfac95dbd7dd9f6255913a1c944f1515d Mon Sep 17 00:00:00 2001 From: Somya Bansal Date: Mon, 28 Aug 2023 22:02:25 +0530 Subject: [PATCH] Added a functionality to highlight subdetectors --- .../src/event-display.ts | 37 +++++- .../three-manager/controls-manager.ts | 32 ++--- .../src/managers/three-manager/index.ts | 52 ++++++-- .../three-manager/selection-manager.ts | 17 +++ .../three-manager/selection-manager.test.ts | 34 +++++ .../lib/components/phoenix-ui.module.ts | 4 + ...collections-info-overlay.component.test.ts | 25 +++- .../collections-info-overlay.component.ts | 8 ++ .../collections-info.component.test.ts | 8 +- .../collections-info.component.ts | 3 + .../geometry-browser-overlay.component.html | 87 +++++++++++++ .../geometry-browser-overlay.component.scss | 120 +++++++++++++++++ ...geometry-browser-overlay.component.test.ts | 122 ++++++++++++++++++ .../geometry-browser-overlay.component.ts | 65 ++++++++++ .../geometry-browser.component.html | 7 + .../geometry-browser.component.scss | 0 .../geometry-browser.component.test.ts | 74 +++++++++++ .../geometry-browser.component.ts | 35 +++++ .../lib/components/ui-menu/index.ts | 2 + .../components/ui-menu/ui-menu.component.html | 3 + 20 files changed, 697 insertions(+), 38 deletions(-) create mode 100644 packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.html create mode 100644 packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.scss create mode 100644 packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.test.ts create mode 100644 packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.ts create mode 100644 packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.html create mode 100644 packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.scss create mode 100644 packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.test.ts create mode 100644 packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.ts diff --git a/packages/phoenix-event-display/src/event-display.ts b/packages/phoenix-event-display/src/event-display.ts index 6c8099b09..313b13ec9 100644 --- a/packages/phoenix-event-display/src/event-display.ts +++ b/packages/phoenix-event-display/src/event-display.ts @@ -653,18 +653,43 @@ export class EventDisplay { * Move the camera to look at the object with the given uuid * and highlight it. * @param uuid uuid of the object. - */ - public lookAtObject(uuid: string) { - this.graphicsLibrary.lookAtObject(uuid); - this.graphicsLibrary.highlightObject(uuid); + * @param detector whether the function is for detector objects or event data. + */ + public lookAtObject(uuid: string, detector: boolean = false) { + if (detector == true) { + this.graphicsLibrary.lookAtObject(uuid, true); + this.graphicsLibrary.highlightObject(uuid, true); + } else { + this.graphicsLibrary.lookAtObject(uuid); + this.graphicsLibrary.highlightObject(uuid); + } } /** * Highlight the object with the given uuid by giving it an outline. * @param uuid uuid of the object. + * @param detector whether the function is for detector objects or event data. + */ + public highlightObject(uuid: string, detector: boolean = false) { + if (detector == true) { + this.graphicsLibrary.highlightObject(uuid, true); + } else { + this.graphicsLibrary.highlightObject(uuid, false); + } + } + + /** + * Enable highlighting of the objects. + */ + public enableHighlighting() { + this.graphicsLibrary.enableHighlighting(); + } + + /** + * Disable highlighting of the objects. */ - public highlightObject(uuid: string) { - this.graphicsLibrary.highlightObject(uuid); + public disableHighlighting() { + this.graphicsLibrary.disableHighlighting(); } /** diff --git a/packages/phoenix-event-display/src/managers/three-manager/controls-manager.ts b/packages/phoenix-event-display/src/managers/three-manager/controls-manager.ts index 7beb60cf9..f8e217f72 100644 --- a/packages/phoenix-event-display/src/managers/three-manager/controls-manager.ts +++ b/packages/phoenix-event-display/src/managers/three-manager/controls-manager.ts @@ -295,26 +295,28 @@ export class ControlsManager { * @param objectsGroup Group of objects to be traversed for finding the object * with the given uuid. */ - public lookAtObject(uuid: string, objectsGroup: Object3D) { + public lookAtObject( + uuid: string, + objectsGroup: Object3D, + offset: number = 0, + ) { const origin = new Vector3(0, 0, 0); const objectPosition = this.getObjectPosition(uuid, objectsGroup); if (objectPosition) { // Check if the object is away from the origin - if (objectPosition.distanceTo(origin) > 0.001) { - for (const camera of this.getAllCameras()) { - // Moving the camera to the object's position and then zooming out - new Tween(camera.position) - .to( - { - x: objectPosition.x * 1.1, - y: objectPosition.y * 1.1, - z: objectPosition.z * 1.1, - }, - 200, - ) - .start(); - } + for (const camera of this.getAllCameras()) { + // Moving the camera to the object's position and then zooming out + new Tween(camera.position) + .to( + { + x: objectPosition.x * 1.1 + offset, + y: objectPosition.y * 1.1 + offset, + z: objectPosition.z * 1.1 + offset, + }, + 200, + ) + .start(); } } } diff --git a/packages/phoenix-event-display/src/managers/three-manager/index.ts b/packages/phoenix-event-display/src/managers/three-manager/index.ts index 7fa16e9b2..1f9d6498f 100644 --- a/packages/phoenix-event-display/src/managers/three-manager/index.ts +++ b/packages/phoenix-event-display/src/managers/three-manager/index.ts @@ -636,12 +636,22 @@ export class ThreeManager { /** * Move the camera to look at the object with the given uuid. * @param uuid uuid of the object. + * @param detector whether the function is for detector objects or event data */ - public lookAtObject(uuid: string) { - this.controlsManager.lookAtObject( - uuid, - this.getSceneManager().getEventData(), - ); + public lookAtObject(uuid: string, detector: boolean = false) { + if (detector == true) { + this.controlsManager.lookAtObject( + uuid, + this.getSceneManager().getGeometries(), + 1000, + ); + } else { + this.controlsManager.lookAtObject( + uuid, + this.getSceneManager().getEventData(), + 0, + ); + } } /** @@ -659,12 +669,34 @@ export class ThreeManager { /** * Highlight the object with the given uuid by giving it an outline. * @param uuid uuid of the object. + * @param detector whether the function is for detector objects or event data. */ - public highlightObject(uuid: string) { - this.selectionManager.highlightObject( - uuid, - this.getSceneManager().getEventData(), - ); + public highlightObject(uuid: string, detector: boolean = false) { + if (detector == true) { + this.selectionManager.highlightObject( + uuid, + this.getSceneManager().getGeometries(), + ); + } else { + this.selectionManager.highlightObject( + uuid, + this.getSceneManager().getEventData(), + ); + } + } + + /** + * Enable the highlighting of the objects. + */ + public enableHighlighting() { + this.selectionManager.enableHighlighting(); + } + + /** + * Disable the highlighting of the objects. + */ + public disableHighlighting() { + this.selectionManager.disableHighlighting(); } /** diff --git a/packages/phoenix-event-display/src/managers/three-manager/selection-manager.ts b/packages/phoenix-event-display/src/managers/three-manager/selection-manager.ts index 9ea2e5acf..54b6859c7 100644 --- a/packages/phoenix-event-display/src/managers/three-manager/selection-manager.ts +++ b/packages/phoenix-event-display/src/managers/three-manager/selection-manager.ts @@ -232,6 +232,14 @@ export class SelectionManager { } } + /** + * Enable highlighting of the objects. + */ + public enableHighlighting() { + this.preSelectionAntialias = this.effectsManager.antialiasing; + this.effectsManager.setAntialiasing(false); + } + /** * Highlight the object with the given uuid by giving it an outline. * @param uuid uuid of the object. @@ -242,6 +250,15 @@ export class SelectionManager { const object = objectsGroup.getObjectByProperty('uuid', uuid); if (object) { this.outlinePass.selectedObjects = [object]; + this.activeObject.update(object.uuid); } } + + /** + * Disable highlighting of objects. + */ + public disableHighlighting() { + this.outlinePass.selectedObjects = []; + this.effectsManager.setAntialiasing(this.preSelectionAntialias); + } } diff --git a/packages/phoenix-event-display/src/tests/managers/three-manager/selection-manager.test.ts b/packages/phoenix-event-display/src/tests/managers/three-manager/selection-manager.test.ts index 2e399233a..41a3b373f 100644 --- a/packages/phoenix-event-display/src/tests/managers/three-manager/selection-manager.test.ts +++ b/packages/phoenix-event-display/src/tests/managers/three-manager/selection-manager.test.ts @@ -92,6 +92,40 @@ describe('SelectionManager', () => { expect(selectionManagerPrivate.disableSelecting).toHaveBeenCalled(); }); + it('should set if highlighting is to be enabled or disabled', () => { + selectionManager['isInit'] = true; + + selectionManager['effectsManager'] = new EffectsManager( + new PerspectiveCamera(), + new Scene(), + new THREE.WebGLRenderer(), + ); + + selectionManager['outlinePass'] = new OutlinePass( + new Vector2(100, 100), + new Scene(), + new PerspectiveCamera(), + ); + + const VALUE1 = selectionManager['effectsManager'].antialiasing; + const spy = jest.spyOn( + selectionManager['effectsManager'], + 'setAntialiasing', + ); + + selectionManager.enableHighlighting(); + + expect(selectionManager['preSelectionAntialias']).toBe(VALUE1); + expect(spy).toHaveBeenCalledWith(false); + + const VALUE2 = selectionManager['preSelectionAntialias']; + + selectionManager.disableHighlighting(); + + expect(selectionManager['outlinePass'].selectedObjects).toStrictEqual([]); + expect(spy).toHaveBeenCalledWith(VALUE2); + }); + it('should highlight the object with the given uuid by giving it an outline', () => { const objectGroup = new Object3D(); jest.spyOn(objectGroup, 'getObjectByProperty'); diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/phoenix-ui.module.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/phoenix-ui.module.ts index a48ae4cad..8058cc6ef 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/phoenix-ui.module.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/phoenix-ui.module.ts @@ -26,6 +26,8 @@ import { UiMenuComponent, CollectionsInfoComponent, MenuToggleComponent, + GeometryBrowserComponent, + GeometryBrowserOverlayComponent, CollectionsInfoOverlayComponent, IoOptionsComponent, IOOptionsDialogComponent, @@ -75,6 +77,8 @@ const PHOENIX_COMPONENTS: Type[] = [ UiMenuWrapperComponent, UiMenuComponent, CollectionsInfoComponent, + GeometryBrowserComponent, + GeometryBrowserOverlayComponent, MenuToggleComponent, CollectionsInfoOverlayComponent, IoOptionsComponent, diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.test.ts index ee62a8906..3c8cf6e32 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.test.ts @@ -4,7 +4,6 @@ import { Object3D } from 'three'; import { CollectionsInfoOverlayComponent } from './collections-info-overlay.component'; import { EventDisplayService } from '../../../../services/event-display.service'; import { PhoenixUIModule } from '../../../phoenix-ui.module'; -import { ElementRef } from '@angular/core'; describe('CollectionsInfoOverlayComponent', () => { let component: CollectionsInfoOverlayComponent; @@ -20,14 +19,16 @@ describe('CollectionsInfoOverlayComponent', () => { callback(); }, }), + enableHighlighting: jest.fn().mockReturnThis(), + disableHighlighting: jest.fn().mockReturnThis(), getThreeManager: jest.fn().mockReturnThis(), getSceneManager: jest.fn().mockReturnThis(), getScene: jest.fn().mockReturnThis(), - getObjectByName: jest.fn(), - getCollection: jest.fn(), - lookAtObject: jest.fn(), - highlightObject: jest.fn(), - addLabelToObject: jest.fn(), + getObjectByName: jest.fn().mockReturnThis(), + getCollection: jest.fn().mockReturnThis(), + lookAtObject: jest.fn().mockReturnThis(), + highlightObject: jest.fn().mockReturnThis(), + addLabelToObject: jest.fn().mockReturnThis(), }; beforeEach(() => { @@ -121,6 +122,18 @@ describe('CollectionsInfoOverlayComponent', () => { expect(mockEventDisplay.highlightObject).toHaveBeenCalledWith(mockUuid); }); + it('should enable highlighting', () => { + component.enableHighlighting(); + + expect(mockEventDisplay.enableHighlighting).toHaveBeenCalled(); + }); + + it('should disable highlighting', () => { + component.disableHighlighting(); + + expect(mockEventDisplay.disableHighlighting).toHaveBeenCalled(); + }); + it('should sort collections in ascending order', () => { const mockCollections = [ ['1235', 'testPropValue'], diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.ts index f03acc26f..8c325cbf0 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.ts @@ -76,6 +76,14 @@ export class CollectionsInfoOverlayComponent implements OnInit { } } + enableHighlighting() { + this.eventDisplay.enableHighlighting(); + } + + disableHighlighting() { + this.eventDisplay.disableHighlighting(); + } + toggleInvisible(checked: boolean) { this.hideInvisible = checked; } diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info.component.test.ts index 085579794..a47fffb0f 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info.component.test.ts @@ -14,7 +14,9 @@ describe('CollectionsInfoComponent', () => { create: jest.fn().mockReturnThis(), attach: jest.fn().mockReturnThis(), overlayWindow: jest.fn().mockReturnThis(), - instance: jest.fn().mockReturnThis(), + instance: { + enableHighlighting: jest.fn(), + }, destroy: jest.fn(), }; @@ -63,5 +65,9 @@ describe('CollectionsInfoComponent', () => { // Expect the overlay window to be visible expect(component.overlayWindow.instance.showObjectsInfo).toBe(true); + + expect( + component.overlayWindow.instance.enableHighlighting, + ).toHaveBeenCalled(); }); }); diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info.component.ts index 072ec1c65..991651d2f 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info.component.ts @@ -28,5 +28,8 @@ export class CollectionsInfoComponent implements OnInit, OnDestroy { toggleOverlay() { this.showObjectsInfo = !this.showObjectsInfo; this.overlayWindow.instance.showObjectsInfo = this.showObjectsInfo; + this.showObjectsInfo + ? this.overlayWindow.instance.enableHighlighting() + : this.overlayWindow.instance.disableHighlighting(); } } diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.html b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.html new file mode 100644 index 000000000..285445fb7 --- /dev/null +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.html @@ -0,0 +1,87 @@ + + + +
+
+
+ Choose a collection: +
+ +
+
+
+ +
+ + + + + + + + + + + + + +
No.Selection
#{{ i }} +
+ + +
+
+

+ Load event data to be able to display information about the collections + here. +

+
+
+
diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.scss b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.scss new file mode 100644 index 000000000..3cc9264bc --- /dev/null +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.scss @@ -0,0 +1,120 @@ +.collectionsInfo { + height: 95%; + + .collectionSelector { + height: 15%; + min-height: 2rem; + + span { + color: var(--phoenix-text-color-secondary); + margin-right: 1rem; + } + } +} + +.boxBody { + height: 85%; + overflow: scroll; + + p.emptyBox { + max-width: 21em; + } +} + +#collectionTable { + position: relative; + color: var(--phoenix-text-color-secondary); + + thead tr th { + position: sticky; + top: 0; + z-index: 100; + background: var(--phoenix-background-color-secondary); + + .row { + margin-right: 10px; + margin-left: -92px; + } + + .icon-wrapper { + display: flex; + width: 1rem; + height: 1rem; + padding: 0.2rem; + + svg { + width: 100%; + height: 100%; + } + } + } + + tr * { + padding-right: 1.2rem; + + &:last-child { + padding-right: 0; + } + } + + tr.active-object { + color: var(--phoenix-background-color); + background: var(--phoenix-text-color); + box-shadow: 0 0 15px var(--phoenix-text-color); + + div.icon-wrapper { + --phoenix-options-icon-path: var(--phoenix-background-color); + --phoenix-options-icon-bg: var(--phoenix-text-color-hover); + } + } + + td { + .object-select { + position: relative; + width: 1.6rem; + height: 1.6rem; + margin-right: 0.4em; + text-align: center; + background-color: var(--phoenix-options-icon-bg); + border-radius: 10px; + cursor: pointer; + + &:last-child { + margin-right: 0; + } + + &:hover { + border: 1px solid var(--phoenix-options-icon-path); + } + + svg { + position: absolute; + top: 0; + left: 0; + padding: 0.4rem; + width: 100%; + height: 100%; + vertical-align: top; + } + } + } +} + +.eventSelector { + display: flex; + + label { + display: none; + color: var(--phoenix-text-color-secondary); + } + + select { + width: 9rem; + padding: 5px 10px; + font-size: 12px; + border: 1px solid rgba(88, 88, 88, 0.08); + box-shadow: var(--phoenix-icon-shadow); + background-color: var(--phoenix-background-color-tertiary); + color: var(--phoenix-text-color-secondary); + } +} diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.test.ts new file mode 100644 index 000000000..fdb57073c --- /dev/null +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.test.ts @@ -0,0 +1,122 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { GeometryBrowserOverlayComponent } from './geometry-browser-overlay.component'; +import { EventDisplayService, PhoenixUIModule } from 'phoenix-ui-components'; +import { ActiveVariable } from 'phoenix-event-display'; +import { Object3D, Event } from 'three'; + +describe('GeometryBrowserOverlayComponent', () => { + let component: GeometryBrowserOverlayComponent; + let fixture: ComponentFixture; + + const mockChild1 = new Object3D(); + mockChild1.name = 'TestCollection'; + mockChild1.children = [new Object3D(), new Object3D()]; + + const mockChild2 = new Object3D(); + mockChild2.name = 'TestCollection2'; + mockChild2.children = [new Object3D(), new Object3D()]; + const mockEventDisplay = { + getActiveObjectId: () => ({ + onUpdate: (callback) => { + callback(); + }, + }), + enableHighlighting: jest.fn().mockReturnThis(), + disableHighlighting: jest.fn().mockReturnThis(), + getThreeManager: jest.fn().mockReturnThis(), + getSceneManager: jest.fn().mockReturnThis(), + getGeometries: jest.fn().mockReturnValue({ + children: [new Object3D(), new Object3D()], + }), + highlightObject: jest.fn().mockReturnThis(), + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [PhoenixUIModule], + providers: [ + { + provide: EventDisplayService, + useValue: mockEventDisplay, + }, + ], + declarations: [GeometryBrowserOverlayComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(GeometryBrowserOverlayComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + + component.activeObject.update = jest.fn(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should initially get active object ID', () => { + const ROW_ID = '1234'; + const activeObjectRow = document.createElement('div'); + activeObjectRow.setAttribute('id', ROW_ID); + document.body.appendChild(activeObjectRow); + + // Return mocked row ID from the getActiveObjectId function same as the element we added above + jest.spyOn(mockEventDisplay, 'getActiveObjectId'); + + component.ngOnInit(); + component.activeObject.value = ROW_ID; + + expect(mockEventDisplay.getActiveObjectId).toHaveBeenCalled(); + }); + + it('should change collection', () => { + const mockChildren = mockEventDisplay + .getThreeManager() + .getSceneManager() + .getGeometries().children; + + const mockSelectedValue = 'TestCollection'; + + component.changeCollection(mockSelectedValue); + + const children: Object3D[] = []; + + for (const child of mockChildren) { + if (child.name === mockSelectedValue) { + children.push(child); + break; + } + } + + expect(component.selectedCollection).toBe(mockSelectedValue); + for (const child of children) { + expect(component.showingCollection).toBe(child.children); + } + }); + + it('should highlight object', () => { + const mockUuid = '123'; // Wrong uuid to cover else + + jest.spyOn(mockEventDisplay, 'highlightObject'); + + component.highlightObject(mockUuid); + + expect(mockEventDisplay.highlightObject).toHaveBeenCalledWith( + mockUuid, + true, + ); + }); + + it('should enable highlighting', () => { + component.enableHighlighting(); + + expect(mockEventDisplay.enableHighlighting).toHaveBeenCalled(); + }); + + it('should disable highlighting', () => { + component.disableHighlighting(); + + expect(mockEventDisplay.disableHighlighting).toHaveBeenCalled(); + }); +}); diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.ts new file mode 100644 index 000000000..91d0cee4a --- /dev/null +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { ActiveVariable } from 'phoenix-event-display'; +import { EventDisplayService } from '../../../../services/event-display.service'; +import { Object3D, Event } from 'three'; + +@Component({ + selector: 'app-geometry-browser-overlay', + templateUrl: './geometry-browser-overlay.component.html', + styleUrls: ['./geometry-browser-overlay.component.scss'], +}) +export class GeometryBrowserOverlayComponent implements OnInit { + @Input() browseDetectorParts: boolean; + selectedCollection: string; + showingCollection: any; + activeObject: ActiveVariable; + children: Object3D[]; + + constructor(private eventDisplay: EventDisplayService) {} + + ngOnInit() { + this.children = this.eventDisplay + .getThreeManager() + .getSceneManager() + .getGeometries().children; + + this.activeObject = this.eventDisplay.getActiveObjectId(); + this.activeObject.onUpdate((value: string) => { + if (document.getElementById(value)) { + document.getElementById(value).scrollIntoView(false); + } + }); + } + + changeCollection(selectedCollection: string) { + this.selectedCollection = selectedCollection; + for (const child of this.children) { + if (child.name === this.selectedCollection) { + this.showingCollection = child.children; + break; + } + } + } + + lookAtObject(uuid: string) { + if (uuid) { + this.activeObject.update(uuid); + this.eventDisplay.lookAtObject(uuid, true); + } + } + + highlightObject(uuid: string) { + if (uuid) { + this.activeObject.update(uuid); + this.eventDisplay.highlightObject(uuid, true); + } + } + + enableHighlighting() { + this.eventDisplay.enableHighlighting(); + } + + disableHighlighting() { + this.eventDisplay.disableHighlighting(); + } +} diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.html b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.html new file mode 100644 index 000000000..da2616290 --- /dev/null +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.html @@ -0,0 +1,7 @@ + + diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.scss b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.test.ts new file mode 100644 index 000000000..349f98f54 --- /dev/null +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.test.ts @@ -0,0 +1,74 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { GeometryBrowserComponent } from './geometry-browser.component'; +import { Overlay } from '@angular/cdk/overlay'; +import { + GeometryBrowserOverlayComponent, + PhoenixUIModule, +} from 'phoenix-ui-components'; +import { ComponentPortal } from '@angular/cdk/portal'; + +describe('GeometryBrowserComponent', () => { + let component: GeometryBrowserComponent; + let fixture: ComponentFixture; + + const mockOverlay = { + create: jest.fn().mockReturnThis(), + attach: jest.fn().mockReturnThis(), + overlayWindow: jest.fn().mockReturnThis(), + instance: { + enableHighlighting: jest.fn(), + }, + destroy: jest.fn(), + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [PhoenixUIModule], + declarations: [GeometryBrowserComponent, GeometryBrowserOverlayComponent], + providers: [ + { + provide: Overlay, + useValue: mockOverlay, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(GeometryBrowserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should create and initialise the overlay', () => { + const overlayRef = mockOverlay.create(); + const overlayPortal = new ComponentPortal(GeometryBrowserOverlayComponent); + + mockOverlay.overlayWindow = overlayRef.attach(overlayPortal); + + component.ngOnInit(); + + expect(component.overlayWindow).toBeTruthy(); + + component.ngOnDestroy(); + expect(component.overlayWindow.destroy).toHaveBeenCalled(); + }); + + it('should toggle geometry browser overlay', () => { + expect(component.browseDetectorParts).toBe(false); + + component.toggleOverlay(); + + expect(component.browseDetectorParts).toBe(true); + + // Expect overlay window to be visible + expect(component.overlayWindow.instance.browseDetectorParts).toBe(true); + + expect( + component.overlayWindow.instance.enableHighlighting, + ).toHaveBeenCalled(); + }); +}); diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.ts new file mode 100644 index 000000000..3bc50e79e --- /dev/null +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser.component.ts @@ -0,0 +1,35 @@ +import { GeometryBrowserOverlayComponent } from './geometry-browser-overlay/geometry-browser-overlay.component'; +import { Component, OnInit, ComponentRef, OnDestroy } from '@angular/core'; +import { Overlay } from '@angular/cdk/overlay'; +import { ComponentPortal } from '@angular/cdk/portal'; + +@Component({ + selector: 'app-geometry-browser', + templateUrl: './geometry-browser.component.html', + styleUrls: ['./geometry-browser.component.scss'], +}) +export class GeometryBrowserComponent implements OnInit, OnDestroy { + browseDetectorParts: boolean = false; + overlayWindow: ComponentRef; + + constructor(private overlay: Overlay) {} + + ngOnInit() { + const overlayRef = this.overlay.create(); + const overlayPortal = new ComponentPortal(GeometryBrowserOverlayComponent); + this.overlayWindow = overlayRef.attach(overlayPortal); + this.overlayWindow.instance.browseDetectorParts = this.browseDetectorParts; + } + + ngOnDestroy(): void { + this.overlayWindow.destroy(); + } + + toggleOverlay() { + this.browseDetectorParts = !this.browseDetectorParts; + this.overlayWindow.instance.browseDetectorParts = this.browseDetectorParts; + this.browseDetectorParts + ? this.overlayWindow.instance.enableHighlighting() + : this.overlayWindow.instance.disableHighlighting(); + } +} diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/index.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/index.ts index a9532be44..50b4566a0 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/index.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/index.ts @@ -3,6 +3,8 @@ export * from './animate-event/animate-event.component'; export * from './auto-rotate/auto-rotate.component'; export * from './collections-info/collections-info.component'; export * from './collections-info/collections-info-overlay/collections-info-overlay.component'; +export * from './geometry-browser/geometry-browser.component'; +export * from './geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component'; export * from './dark-theme/dark-theme.component'; export * from './event-selector/event-selector.component'; export * from './experiment-info/experiment-info.component'; diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/ui-menu.component.html b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/ui-menu.component.html index 50c5163c7..4d1d3fcb2 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/ui-menu.component.html +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/ui-menu.component.html @@ -38,6 +38,9 @@ + + +