Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Playground: Implement a splitscreen #27784

Merged
merged 1 commit into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions playground/NodeEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Canvas, CircleMenu, ButtonInput, StringInput, ContextMenu, Tips, Search
import { FileEditor } from './editors/FileEditor.js';
import { exportJSON } from './NodeEditorUtils.js';
import { init, ClassLib, getNodeEditorClass, getNodeList } from './NodeEditorLib.js';
import { SplitscreenManager } from './SplitscreenManager.js';

init();

Expand Down Expand Up @@ -38,6 +39,7 @@ export class NodeEditor extends THREE.EventDispatcher {
this.domElement = domElement;

this._preview = false;
this._splitscreen = false;

this.search = null;

Expand All @@ -47,6 +49,7 @@ export class NodeEditor extends THREE.EventDispatcher {
this.nodesContext = null;
this.examplesContext = null;

this._initSplitview();
this._initUpload();
this._initTips();
this._initMenu();
Expand All @@ -55,7 +58,6 @@ export class NodeEditor extends THREE.EventDispatcher {
this._initExamplesContext();
this._initShortcuts();
this._initParams();

}

setSize( width, height ) {
Expand Down Expand Up @@ -113,6 +115,9 @@ export class NodeEditor extends THREE.EventDispatcher {

if ( value ) {

this._wasSplitscreen = this.splitscreen;
this.splitscreen = false;

this.menu.dom.remove();
this.canvas.dom.remove();
this.search.dom.remove();
Expand All @@ -129,6 +134,12 @@ export class NodeEditor extends THREE.EventDispatcher {

this.previewMenu.dom.remove();

if (this._wasSplitscreen == true) {

this.splitscreen = true;

}

}

this._preview = value;
Expand All @@ -141,6 +152,22 @@ export class NodeEditor extends THREE.EventDispatcher {

}

set splitscreen( value ) {

if ( this._splitscreen === value ) return;

this.splitview.setSplitview( value );

this._splitscreen = value;

}

get splitscreen() {

return this._splitscreen;

}

newProject() {

const canvas = this.canvas;
Expand Down Expand Up @@ -180,6 +207,12 @@ export class NodeEditor extends THREE.EventDispatcher {

}

_initSplitview() {

this.splitview = new SplitscreenManager( this );

}

_initUpload() {

const canvas = this.canvas;
Expand Down Expand Up @@ -231,6 +264,7 @@ export class NodeEditor extends THREE.EventDispatcher {
previewMenu.setAlign( 'top left' );

const previewButton = new ButtonInput().setIcon( 'ti ti-brand-threejs' ).setToolTip( 'Preview' );
const splitscreenButton = new ButtonInput().setIcon( 'ti ti-layout-sidebar-right-expand' ).setToolTip( 'Splitscreen' );
const menuButton = new ButtonInput().setIcon( 'ti ti-apps' ).setToolTip( 'Add' );
const examplesButton = new ButtonInput().setIcon( 'ti ti-file-symlink' ).setToolTip( 'Examples' );
const newButton = new ButtonInput().setIcon( 'ti ti-file' ).setToolTip( 'New' );
Expand All @@ -242,6 +276,13 @@ export class NodeEditor extends THREE.EventDispatcher {
previewButton.onClick( () => this.preview = true );
editorButton.onClick( () => this.preview = false );

splitscreenButton.onClick( () => {

this.splitscreen = !this.splitscreen;
splitscreenButton.setIcon(this.splitscreen ? 'ti ti-layout-sidebar-right-collapse' : 'ti ti-layout-sidebar-right-expand');

});

menuButton.onClick( () => this.nodesContext.open() );
examplesButton.onClick( () => this.examplesContext.open() );

Expand Down Expand Up @@ -289,6 +330,7 @@ export class NodeEditor extends THREE.EventDispatcher {
} );

menu.add( previewButton )
.add( splitscreenButton )
.add( newButton )
.add( examplesButton )
.add( openButton )
Expand All @@ -297,7 +339,7 @@ export class NodeEditor extends THREE.EventDispatcher {

previewMenu.add( editorButton );

this.domElement.append( menu.dom );
this.domElement.appendChild(menu.dom);

this.menu = menu;
this.previewMenu = previewMenu;
Expand Down
91 changes: 91 additions & 0 deletions playground/SplitscreenManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
export class SplitscreenManager {

constructor( editor ) {

this.editor = editor;
this.renderer = editor.renderer;
this.composer = editor.composer;

this.gutter = null;
this.gutterMoving = false;
this.gutterOffset = 0.75;

}

setSplitview( value ) {

const nodeDOM = this.editor.domElement;
const rendererContainer = this.renderer.domElement.parentNode;

if ( value ) {

this.addGutter( rendererContainer, nodeDOM );

} else {

this.removeGutter( rendererContainer, nodeDOM );

}

}

addGutter( rendererContainer, nodeDOM ) {

rendererContainer.style[ "z-index" ] = 20;

this.gutter = document.createElement( "f-gutter" );

nodeDOM.parentNode.appendChild( this.gutter );

const onGutterMovement = () => {

const offset = this.gutterOffset;

this.gutter.style[ "left" ] = 100 * offset + '%';
rendererContainer.style[ "left" ] = 100 * offset + '%';
rendererContainer.style[ "width" ] = 100 * (1 - offset) + '%';
nodeDOM.style[ "width" ] = 100 * offset + '%';

}

this.gutter.addEventListener( 'mousedown', ( event ) => {

this.gutterMoving = true;

} );

document.addEventListener( 'mousemove', ( event ) => {

if ( this.gutter && this.gutterMoving ) {

this.gutterOffset = Math.max(0, Math.min(1, event.clientX / window.innerWidth));
onGutterMovement();

}

} );

document.addEventListener( 'mouseup', ( event ) => {

this.gutterMoving = false;

});

onGutterMovement();

}

removeGutter( rendererContainer, nodeDOM ) {

rendererContainer.style[ "z-index" ] = 0;

this.gutter.remove();
this.gutter = null;

rendererContainer.style[ "left" ] = '0%';
rendererContainer.style[ "width" ] = '100%';
nodeDOM.style[ "width" ] = '100%';

}

}
91 changes: 76 additions & 15 deletions playground/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
margin: 0;
position: fixed;
overscroll-behavior: none;
background: #191919ed;
}

.renderer {
Expand All @@ -35,6 +36,7 @@
width: 100%;
box-shadow: inset 0 0 20px 0px #000000;
pointer-events: none;
overflow: hidden;
}

flow > * {
Expand All @@ -49,6 +51,43 @@
background: #191919ed;
}

flow f-menu {
white-space: nowrap;
}

node-editor {
position: relative;
width: 100%;
height: 100%;
}

f-preview {
display: block;
position: relative;
width: 100%;
height: 100%;
}

f-gutter {
position: absolute;
cursor: ew-resize;
height: 100%;
top: 0px;
width: 2px;
background-color: #191919ed;
border-style: none solid none solid;
border-width: 1px;
border-color: #aaaaaa;
box-shadow: 0 0 5px 0px #000000;
z-index: 30;
}

.panel {
position: absolute;
overflow: visible;
float: left;
}

</style>
</head>
<body>
Expand Down Expand Up @@ -86,6 +125,10 @@

async function init() {

const container = document.createElement( 'node-editor' );

document.body.appendChild( container );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use this.domElement instead of document.body here and in others appends? This would make the editor more flexible if we added it embed in editor for exemple. I think we can do the same thing with the classes, for example: flow splitview intead of just splitview.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.domElement is null in the context of the script (which is directly embedded into the html). Thus, I am not sure how to implement that, can you give me a hint?


const urlParams = new URLSearchParams( window.location.search );
const backend = urlParams.get( 'backend' );

Expand Down Expand Up @@ -128,9 +171,13 @@
renderer.setAnimationLoop( render );
renderer.toneMapping = THREE.LinearToneMapping;
renderer.toneMappingExposure = 1;
document.body.appendChild( renderer.domElement );

renderer.domElement.className = 'renderer';
// Additional container required for determining accurate pixel dimensions of the canvas when resizing
const rendererContainer = document.createElement( 'f-preview' );
container.appendChild( rendererContainer );

rendererContainer.appendChild( renderer.domElement );
renderer.domElement.className = 'renderer panel';

//

Expand All @@ -140,13 +187,13 @@

window.addEventListener( 'resize', onWindowResize );

initEditor();
initEditor(container);

onWindowResize();

}

function initEditor() {
function initEditor(container) {

nodeEditor = new NodeEditor( scene, renderer, composer );

Expand All @@ -156,22 +203,15 @@

} );

document.body.appendChild( nodeEditor.domElement );
container.appendChild( nodeEditor.domElement );
nodeEditor.domElement.className = 'panel';

}

function onWindowResize() {

const width = window.innerWidth;
const height = window.innerHeight;

camera.aspect = width / height;
camera.updateProjectionMatrix();

renderer.setSize( width, height );
if ( composer ) composer.setSize( width, height );

nodeEditor.setSize( width, height );
checkResize();
nodeEditor.setSize( window.innerWidth, window.innerHeight );

}

Expand All @@ -189,11 +229,32 @@

function render() {

checkResize();

if ( composer && composer.passes.length > 1 ) composer.render();
else renderer.render( scene, camera );

}

function checkResize() {

const canvas = renderer.domElement;

const rendererContainer = canvas.parentNode;
const width = rendererContainer.clientWidth;
const height = rendererContainer.clientHeight;

if ( canvas.width !== width || canvas.height !== height ) {

camera.aspect = width / height;
camera.updateProjectionMatrix();

renderer.setSize( width , height );
if ( composer ) composer.setSize( width, height );

}
}

</script>

</body>
Expand Down