Skip to content

Commit

Permalink
feat(controls): Add React controls for Image360 (#1388)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conrad Chan authored May 25, 2021
1 parent 9604879 commit 09fadfa
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 5 deletions.
6 changes: 4 additions & 2 deletions src/lib/viewers/box3d/Box3DViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ class Box3DViewer extends BaseViewer {
* @return {void}
*/
handleSceneLoaded() {
if (this.controls) {
if (this.controls && !this.getViewerOption('useReactControls')) {
this.controls.addUi();
}
this.emit(EVENT_LOAD);
Expand All @@ -326,7 +326,9 @@ class Box3DViewer extends BaseViewer {
* @return {void}
*/
handleShowVrButton() {
this.controls.showVrButton();
if (this.controls && !this.getViewerOption('useReactControls')) {
this.controls.showVrButton();
}
}

/**
Expand Down
31 changes: 30 additions & 1 deletion src/lib/viewers/box3d/__tests__/Box3DViewer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -529,12 +529,41 @@ describe('lib/viewers/box3d/Box3DViewer', () => {
box3d.handleSceneLoaded();
expect(box3d.controls.addUi).toBeCalled();
});

describe('With react controls', () => {
beforeEach(() => {
jest.spyOn(box3d, 'getViewerOption').mockImplementation(() => true);
});

test('should not call addUi', () => {
box3d.handleSceneLoaded();

expect(box3d.controls.addUi).not.toBeCalled();
});
});
});

describe('handleShowVrButton()', () => {
test('should call controls.showVrButton()', () => {
beforeEach(() => {
box3d.controls.showVrButton = jest.fn();
});

test('should call controls.showVrButton()', () => {
box3d.handleShowVrButton();

expect(box3d.controls.showVrButton).toBeCalled();
});

describe('With react controls', () => {
beforeEach(() => {
jest.spyOn(box3d, 'getViewerOption').mockImplementation(() => true);
});

test('should not call addUi', () => {
box3d.handleShowVrButton();

expect(box3d.controls.showVrButton).not.toBeCalled();
});
});
});

Expand Down
15 changes: 15 additions & 0 deletions src/lib/viewers/box3d/image360/Image360Controls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import ControlsBar from '../../controls/controls-bar';
import FullscreenToggle, { Props as FullscreenToggleProps } from '../../controls/fullscreen';
import VrToggleControl, { Props as VrToggleConrolProps } from '../../controls/box3d/VrToggleControl';

export type Props = FullscreenToggleProps & VrToggleConrolProps;

export default function Image360Controls({ isVrShown, onFullscreenToggle, onVrToggle }: Props): JSX.Element {
return (
<ControlsBar>
<FullscreenToggle onFullscreenToggle={onFullscreenToggle} />
<VrToggleControl isVrShown={isVrShown} onVrToggle={onVrToggle} />
</ControlsBar>
);
}
50 changes: 48 additions & 2 deletions src/lib/viewers/box3d/image360/Image360Viewer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import './Image360.scss';
import React from 'react';
import Box3DViewer from '../Box3DViewer';
import Box3DControls from '../Box3DControls';
import ControlsRoot from '../../controls/controls-root';
import Image360Controls from './Image360Controls';
import Image360Renderer from './Image360Renderer';
import './Image360.scss';

const CSS_CLASS_IMAGE_360 = 'bp-image-360';
const LOAD_TIMEOUT = 120000;
Expand Down Expand Up @@ -30,9 +33,52 @@ class Image360Viewer extends Box3DViewer {
* @inheritdoc
*/
createSubModules() {
this.controls = new Box3DControls(this.wrapperEl);
this.controls = this.getViewerOption('useReactControls')
? new ControlsRoot({ containerEl: this.wrapperEl, fileId: this.options.file.id })
: new Box3DControls(this.wrapperEl);
this.renderer = new Image360Renderer(this.wrapperEl, this.boxSdk, { api: this.api });
}

/**
* @inheritdoc
*/
handleSceneLoaded() {
super.handleSceneLoaded();

if (this.getViewerOption('useReactControls')) {
this.renderUI();
}
}

/**
* @inheritdoc
*/
handleShowVrButton() {
if (!this.controls) {
return;
}

if (this.getViewerOption('useReactControls')) {
this.showVrButton = true;
this.renderUI();
} else {
this.controls.showVrButton();
}
}

renderUI() {
if (!this.controls) {
return;
}

this.controls.render(
<Image360Controls
isVrShown={this.showVrButton}
onFullscreenToggle={this.toggleFullscreen}
onVrToggle={this.handleToggleVr}
/>,
);
}
}

export default Image360Viewer;
34 changes: 34 additions & 0 deletions src/lib/viewers/box3d/image360/__tests__/Image360Controls-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
import FullscreenToggle from '../../../controls/fullscreen';
import Image360Controls, { Props } from '../Image360Controls';
import VrToggleControl from '../../../controls/box3d/VrToggleControl';

describe('lib/viewers/box3d/image360/Image360Controls', () => {
const getDefaults = (): Props => ({
isVrShown: false,
onFullscreenToggle: jest.fn(),
onVrToggle: jest.fn(),
});

const getWrapper = (props: Partial<Props>): ShallowWrapper =>
shallow(<Image360Controls {...getDefaults()} {...props} />);

describe('render()', () => {
test('should return a valid wrapper', () => {
const onFullscreenToggle = jest.fn();
const onVrToggle = jest.fn();

const wrapper = getWrapper({
onFullscreenToggle,
onVrToggle,
});

expect(wrapper.find(VrToggleControl).props()).toMatchObject({
isVrShown: false,
onVrToggle,
});
expect(wrapper.find(FullscreenToggle).prop('onFullscreenToggle')).toEqual(onFullscreenToggle);
});
});
});
91 changes: 91 additions & 0 deletions src/lib/viewers/box3d/image360/__tests__/Image360Viewer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import Image360Viewer from '../Image360Viewer';
import BaseViewer from '../../../BaseViewer';
import Box3DControls from '../../Box3DControls';
import ControlsRoot from '../../../controls';
import Image360Renderer from '../Image360Renderer';
import { SELECTOR_BOX_PREVIEW_CONTENT } from '../../../../constants';

Expand Down Expand Up @@ -62,5 +63,95 @@ describe('lib/viewers/box3d/image360/Image360Viewer', () => {
test('should create Image360Renderer instance and assign to .renderer', () => {
expect(viewer.renderer).toBeInstanceOf(Image360Renderer);
});

describe('With react controls', () => {
beforeEach(() => {
jest.spyOn(viewer, 'getViewerOption').mockImplementation(() => true);
});

test('should create ControlsRoot instance and assign to .controls', () => {
viewer.createSubModules();
expect(viewer.controls).toBeInstanceOf(ControlsRoot);
});
});
});

describe('handleSceneLoaded()', () => {
beforeEach(() => {
jest.spyOn(viewer, 'getViewerOption').mockImplementation(() => true);
jest.spyOn(viewer, 'renderUI');
});

test('should render the react UI', () => {
viewer.handleSceneLoaded();
expect(viewer.renderUI).toBeCalled();
});

describe('Without react controls', () => {
beforeEach(() => {
jest.spyOn(viewer, 'getViewerOption').mockImplementation(() => false);
});

test('should render the react UI', () => {
viewer.handleSceneLoaded();
expect(viewer.renderUI).not.toBeCalled();
});
});
});

describe('handleShowVrButton()', () => {
beforeEach(() => {
jest.spyOn(viewer, 'getViewerOption').mockImplementation(() => true);
jest.spyOn(viewer, 'renderUI');

viewer.setup();
viewer.createSubModules();
});

test('should render the react UI', () => {
viewer.handleShowVrButton();

expect(viewer.showVrButton).toBe(true);
expect(viewer.renderUI).toBeCalled();
});

describe('Without react controls', () => {
beforeEach(() => {
jest.spyOn(viewer, 'getViewerOption').mockImplementation(() => false);

viewer.createSubModules();

jest.spyOn(viewer.controls, 'showVrButton');
});

test('should call showVrButton on the controls', () => {
viewer.handleShowVrButton();

expect(viewer.renderUI).not.toBeCalled();
expect(viewer.controls.showVrButton).toBeCalled();
});
});
});

describe('renderUI()', () => {
const getProps = instance => instance.controls.render.mock.calls[0][0].props;

beforeEach(() => {
jest.spyOn(viewer, 'getViewerOption').mockImplementation(() => true);
viewer.controls = {
destroy: jest.fn(),
render: jest.fn(),
};
});

test('should render react controls with the correct props', () => {
viewer.renderUI();

expect(getProps(viewer)).toMatchObject({
isVrShown: false,
onFullscreenToggle: viewer.toggleFullscreen,
onVrToggle: viewer.handleToggleVr,
});
});
});
});

0 comments on commit 09fadfa

Please sign in to comment.