Fix and enable 3D viewer: #4035
Fix 3d viewer styles Fix minor warnings from three.js Remove deprecated themes Fix #4074
This commit is contained in:
parent
ae3c8d5221
commit
e4d822f818
6 changed files with 79 additions and 154 deletions
|
@ -2,6 +2,7 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import FileRender from 'component/fileRender';
|
import FileRender from 'component/fileRender';
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
||||||
|
import { NON_STREAM_MODES } from 'constants/file_render_modes';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isPlaying: boolean,
|
isPlaying: boolean,
|
||||||
|
@ -14,9 +15,18 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function FileRenderInline(props: Props) {
|
export default function FileRenderInline(props: Props) {
|
||||||
const { isPlaying, fileInfo, uri, streamingUrl, triggerAnalyticsView, claimRewards } = props;
|
const { isPlaying, fileInfo, uri, streamingUrl, triggerAnalyticsView, claimRewards, renderMode } = props;
|
||||||
const [playTime, setPlayTime] = useState();
|
const [playTime, setPlayTime] = useState();
|
||||||
const isReadyToPlay = streamingUrl || (fileInfo && fileInfo.completed);
|
const isReadyToView = fileInfo && fileInfo.completed;
|
||||||
|
const isReadyToPlay = streamingUrl || isReadyToView;
|
||||||
|
|
||||||
|
// Render if any source is ready
|
||||||
|
let renderContent = isReadyToPlay;
|
||||||
|
|
||||||
|
// Force non-streaming content to wait for download
|
||||||
|
if (NON_STREAM_MODES.includes(renderMode)) {
|
||||||
|
renderContent = isReadyToView;
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
|
@ -39,5 +49,5 @@ export default function FileRenderInline(props: Props) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isReadyToPlay ? <FileRender uri={uri} /> : <LoadingScreen status={__('Preparing your content')} />;
|
return renderContent ? <FileRender uri={uri} /> : <LoadingScreen status={__('Preparing your content')} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import * as dat from 'dat.gui';
|
import * as dat from 'dat.gui';
|
||||||
import classNames from 'classnames';
|
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
||||||
|
|
||||||
// ThreeJS
|
// ThreeJS
|
||||||
|
@ -52,14 +51,13 @@ const ThreeLoader = ({ fileType = null, downloadPath = null }, renderModel, mana
|
||||||
};
|
};
|
||||||
|
|
||||||
type viewerTheme = {
|
type viewerTheme = {
|
||||||
gridColor: string,
|
showFog: boolean,
|
||||||
groundColor: string,
|
gridColor: number,
|
||||||
backgroundColor: string,
|
backgroundColor: number,
|
||||||
centerLineColor: string,
|
centerLineColor: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
theme: string,
|
|
||||||
source: {
|
source: {
|
||||||
fileType: string,
|
fileType: string,
|
||||||
downloadPath: string,
|
downloadPath: string,
|
||||||
|
@ -131,26 +129,15 @@ class ThreeViewer extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
const { theme } = this.props;
|
|
||||||
// Object defualt color
|
// Object defualt color
|
||||||
this.materialColor = '#44b098';
|
this.materialColor = 0xffffff;
|
||||||
// Viewer themes
|
// Default viewer Theme
|
||||||
this.themes = {
|
this.theme = {
|
||||||
dark: {
|
showFog: true,
|
||||||
gridColor: '#414e5c',
|
gridColor: 0x414e5c,
|
||||||
groundColor: '#13233C',
|
centerLineColor: 0x7f8c8d,
|
||||||
backgroundColor: '#13233C',
|
backgroundColor: 0x0b0c0d,
|
||||||
centerLineColor: '#7f8c8d',
|
|
||||||
},
|
|
||||||
light: {
|
|
||||||
gridColor: '#7f8c8d',
|
|
||||||
groundColor: '#DDD',
|
|
||||||
backgroundColor: '#EEE',
|
|
||||||
centerLineColor: '#2F2F2F',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
// Select current theme
|
|
||||||
this.theme = this.themes[theme] || this.themes.light;
|
|
||||||
// State
|
// State
|
||||||
this.state = {
|
this.state = {
|
||||||
error: null,
|
error: null,
|
||||||
|
@ -212,29 +199,27 @@ class ThreeViewer extends React.PureComponent<Props, State> {
|
||||||
});
|
});
|
||||||
// Clean up controls
|
// Clean up controls
|
||||||
if (this.controls) this.controls.dispose();
|
if (this.controls) this.controls.dispose();
|
||||||
// It's unclear if we need this:
|
// Clean up scene
|
||||||
|
if (this.scene) this.scene.dispose();
|
||||||
|
|
||||||
if (this.renderer) {
|
if (this.renderer) {
|
||||||
|
this.renderer.context = null;
|
||||||
|
this.renderer.domElement = null;
|
||||||
this.renderer.renderLists.dispose();
|
this.renderer.renderLists.dispose();
|
||||||
|
this.renderer.forceContextLoss();
|
||||||
this.renderer.dispose();
|
this.renderer.dispose();
|
||||||
|
this.renderer = null;
|
||||||
}
|
}
|
||||||
// Stop animation
|
// Stop animation
|
||||||
cancelAnimationFrame(this.frameID);
|
cancelAnimationFrame(this.frameID);
|
||||||
// Destroy GUI Controls
|
// Destroy GUI Controls
|
||||||
if (this.gui) this.gui.destroy();
|
if (this.gui) this.gui.destroy();
|
||||||
// Empty objects
|
|
||||||
this.grid = null;
|
|
||||||
this.mesh = null;
|
|
||||||
this.renderer = null;
|
|
||||||
this.material = null;
|
|
||||||
this.geometry = null;
|
|
||||||
this.bufferGeometry = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define component types
|
// Define component types
|
||||||
theme: viewerTheme;
|
theme: viewerTheme;
|
||||||
themes: { dark: viewerTheme, light: viewerTheme };
|
materialColor: number;
|
||||||
materialColor: string;
|
|
||||||
// Refs
|
// Refs
|
||||||
viewer: ?HTMLElement;
|
viewer: ?HTMLElement;
|
||||||
guiContainer: ?HTMLElement;
|
guiContainer: ?HTMLElement;
|
||||||
|
@ -265,10 +250,10 @@ class ThreeViewer extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
transformGroup(group: any) {
|
transformGroup(group: any) {
|
||||||
ThreeViewer.fitMeshToCamera(group);
|
ThreeViewer.fitMeshToCamera(group);
|
||||||
|
|
||||||
if (!this.targetCenter) {
|
if (!this.targetCenter) {
|
||||||
const box = new Box3();
|
const box = new Box3();
|
||||||
this.targetCenter = box.setFromObject(this.mesh).getCenter();
|
const center = new Vector3();
|
||||||
|
this.targetCenter = box.setFromObject(this.mesh).getCenter(center);
|
||||||
}
|
}
|
||||||
this.updateControlsTarget(this.targetCenter);
|
this.updateControlsTarget(this.targetCenter);
|
||||||
}
|
}
|
||||||
|
@ -452,10 +437,7 @@ class ThreeViewer extends React.PureComponent<Props, State> {
|
||||||
gammaCorrection: true,
|
gammaCorrection: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.scene = ThreeScene({
|
this.scene = ThreeScene(this.theme);
|
||||||
showFog: true,
|
|
||||||
...this.theme,
|
|
||||||
});
|
|
||||||
|
|
||||||
const canvas = this.renderer.domElement;
|
const canvas = this.renderer.domElement;
|
||||||
const { offsetWidth: width, offsetHeight: height } = this.viewer || {};
|
const { offsetWidth: width, offsetHeight: height } = this.viewer || {};
|
||||||
|
@ -473,7 +455,7 @@ class ThreeViewer extends React.PureComponent<Props, State> {
|
||||||
// Set viewer size
|
// Set viewer size
|
||||||
this.renderer.setSize(width, height);
|
this.renderer.setSize(width, height);
|
||||||
|
|
||||||
// Create model material
|
// Create material
|
||||||
this.material = new MeshPhongMaterial({
|
this.material = new MeshPhongMaterial({
|
||||||
depthWrite: true,
|
depthWrite: true,
|
||||||
flatShading: true,
|
flatShading: true,
|
||||||
|
@ -501,26 +483,21 @@ class ThreeViewer extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { theme } = this.props;
|
|
||||||
const { error, isReady, isLoading } = this.state;
|
const { error, isReady, isLoading } = this.state;
|
||||||
const loadingMessage = __('Loading 3D model.');
|
const loadingMessage = __('Loading 3D model.');
|
||||||
const showViewer = isReady && !error;
|
const showLoading = isLoading && !error && !isReady;
|
||||||
const showLoading = isLoading && !error;
|
const containerClass = 'gui-container';
|
||||||
|
|
||||||
// Adaptive theme for gui controls
|
|
||||||
const containerClass = classNames('gui-container', { light: theme === 'light' });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<>
|
||||||
|
<div className="file-render__viewer file-render__viewer--three">
|
||||||
|
<div ref={element => (this.guiContainer = element)} className={containerClass} />
|
||||||
|
<div className="three-viewer" ref={viewer => (this.viewer = viewer)}>
|
||||||
{error && <LoadingScreen status={error} spinner={false} />}
|
{error && <LoadingScreen status={error} spinner={false} />}
|
||||||
{showLoading && <LoadingScreen status={loadingMessage} spinner />}
|
{showLoading && <LoadingScreen status={loadingMessage} spinner />}
|
||||||
<div ref={element => (this.guiContainer = element)} className={containerClass} />
|
</div>
|
||||||
<div
|
</div>
|
||||||
style={{ opacity: showViewer ? 1 : 0 }}
|
</>
|
||||||
className="three-viewer file-render__viewer"
|
|
||||||
ref={viewer => (this.viewer = viewer)}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,17 +21,18 @@ const addLights = (scene, color, groundColor) => {
|
||||||
scene.add(shadowLight);
|
scene.add(shadowLight);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ViewerScene = ({ backgroundColor, groundColor, showFog }) => {
|
const ViewerScene = ({ backgroundColor, showFog }) => {
|
||||||
// Convert color
|
|
||||||
const bgColor = new Color(backgroundColor);
|
|
||||||
// New scene
|
// New scene
|
||||||
|
const bg = new Color(backgroundColor);
|
||||||
const scene = new Scene();
|
const scene = new Scene();
|
||||||
// Background color
|
// Transparent background
|
||||||
scene.background = bgColor;
|
scene.background = bg;
|
||||||
// Fog effect
|
// Add fog
|
||||||
scene.fog = showFog === true ? new Fog(bgColor, 1, 95) : null;
|
if (showFog) {
|
||||||
|
scene.fog = new Fog(bg, 1, 54);
|
||||||
|
}
|
||||||
// Add basic lights
|
// Add basic lights
|
||||||
addLights(scene, '#FFFFFF', groundColor);
|
addLights(scene, 0xffffff, bg);
|
||||||
// Return new three scene
|
// Return new three scene
|
||||||
return scene;
|
return scene;
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,7 +16,10 @@ export const IMAGE = 'image';
|
||||||
export const CAD = 'cad';
|
export const CAD = 'cad';
|
||||||
export const COMIC = 'comic';
|
export const COMIC = 'comic';
|
||||||
|
|
||||||
export const AUTO_RENDER_MODES = [IMAGE, CAD, COMIC].concat(TEXT_MODES); // these types will render (and thus download) automatically (if free)
|
// These types can only be render if download completed
|
||||||
|
export const NON_STREAM_MODES = [CAD, COMIC];
|
||||||
|
|
||||||
|
export const AUTO_RENDER_MODES = [IMAGE].concat(TEXT_MODES);
|
||||||
export const WEB_SHAREABLE_MODES = AUTO_RENDER_MODES.concat(FLOATING_MODES);
|
export const WEB_SHAREABLE_MODES = AUTO_RENDER_MODES.concat(FLOATING_MODES);
|
||||||
|
|
||||||
export const DOWNLOAD = 'download';
|
export const DOWNLOAD = 'download';
|
||||||
|
@ -25,7 +28,7 @@ export const UNSUPPORTED = 'unsupported';
|
||||||
|
|
||||||
// PDFs disabled on desktop until we update Electron: https://github.com/electron/electron/issues/12337
|
// PDFs disabled on desktop until we update Electron: https://github.com/electron/electron/issues/12337
|
||||||
// Comics disabled because nothing is actually reporting as a comic type
|
// Comics disabled because nothing is actually reporting as a comic type
|
||||||
export const UNSUPPORTED_IN_THIS_APP = IS_WEB ? [CAD, COMIC, APPLICATION] : [CAD, APPLICATION, PDF];
|
export const UNSUPPORTED_IN_THIS_APP = IS_WEB ? [CAD, COMIC, APPLICATION] : [APPLICATION, PDF];
|
||||||
|
|
||||||
export const UNRENDERABLE_MODES = Array.from(
|
export const UNRENDERABLE_MODES = Array.from(
|
||||||
new Set(UNSUPPORTED_IN_THIS_APP.concat([DOWNLOAD, APPLICATION, UNSUPPORTED]))
|
new Set(UNSUPPORTED_IN_THIS_APP.concat([DOWNLOAD, APPLICATION, UNSUPPORTED]))
|
||||||
|
|
|
@ -3,101 +3,26 @@
|
||||||
.gui-container {
|
.gui-container {
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2;
|
|
||||||
|
|
||||||
.dg.main {
|
.dg.main {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: inherit;
|
overflow: inherit;
|
||||||
}
|
|
||||||
|
|
||||||
// Light theme:
|
|
||||||
// https://github.com/liabru/dat-gui-light-theme
|
|
||||||
|
|
||||||
&.light {
|
|
||||||
.dg.main.taller-than-window .close-button {
|
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dg.main .close-button {
|
|
||||||
&:not(:hover) {
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #ddd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dg {
|
|
||||||
color: #555;
|
|
||||||
text-shadow: none !important;
|
|
||||||
|
|
||||||
&.main {
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
background-color: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background-color: #bbb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
li {
|
||||||
&:not(.folder) {
|
margin: 0;
|
||||||
background-color: #fafafa;
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.save-row .button {
|
|
||||||
text-shadow: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.title {
|
|
||||||
background: #e8e8e8
|
|
||||||
url('data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==')
|
|
||||||
6px 10px no-repeat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cr {
|
|
||||||
&.function:hover,
|
|
||||||
&.boolean:hover {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.c {
|
|
||||||
input {
|
input {
|
||||||
&[type='text'] {
|
height: initial;
|
||||||
&:not(:focus),
|
|
||||||
&:not(:hover) {
|
|
||||||
background-color: #e9e9e9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus,
|
input[type='checkbox'] {
|
||||||
&:hover {
|
height: 12px;
|
||||||
background-color: #eee;
|
width: 12px;
|
||||||
}
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
&:focus {
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider {
|
|
||||||
&:not(:hover) {
|
|
||||||
background-color: #e9e9e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #eee;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.file-render__viewer--three {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.three-viewer {
|
||||||
|
height: calc(100vh - var(--header-height) - var(--spacing-medium) * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.file-render__content {
|
.file-render__content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
Loading…
Add table
Reference in a new issue