From 1b65f2280282fafb5291fd2c745d1c49aaa7b190 Mon Sep 17 00:00:00 2001 From: Viktor Kovacs Date: Mon, 12 Dec 2022 22:38:41 +0100 Subject: [PATCH] New sidebar resize logic #336 --- source/website/index.js | 2 + source/website/navigator.js | 31 +++--- source/website/sidebar.js | 29 ++---- source/website/utils.js | 30 +----- source/website/website.js | 200 +++++++++++++++++++++++++++--------- website/css/website.css | 14 ++- website/index.html | 12 ++- 7 files changed, 197 insertions(+), 121 deletions(-) diff --git a/source/website/index.js b/source/website/index.js index e0e654f..3c36ced 100644 --- a/source/website/index.js +++ b/source/website/index.js @@ -42,8 +42,10 @@ export function StartWebsite (externalLibLocation) mainDiv : document.getElementById ('main'), introDiv : document.getElementById ('intro'), fileNameDiv : document.getElementById ('main_file_name'), + leftContainerDiv : document.getElementById ('main_left_container'), navigatorDiv : document.getElementById ('main_navigator'), navigatorSplitterDiv : document.getElementById ('main_navigator_splitter'), + rightContainerDiv : document.getElementById ('main_right_container'), sidebarDiv : document.getElementById ('main_sidebar'), sidebarSplitterDiv : document.getElementById ('main_sidebar_splitter'), viewerDiv : document.getElementById ('main_viewer'), diff --git a/source/website/navigator.js b/source/website/navigator.js index 092a02e..36a8534 100644 --- a/source/website/navigator.js +++ b/source/website/navigator.js @@ -1,9 +1,8 @@ -import { ShowDomElement, SetDomElementHeight, GetDomElementOuterWidth, SetDomElementOuterHeight } from '../engine/viewer/domutils.js'; +import { GetDomElementOuterWidth, SetDomElementOuterHeight, SetDomElementOuterWidth } from '../engine/viewer/domutils.js'; import { NavigatorFilesPanel } from './navigatorfilespanel.js'; import { NavigatorMaterialsPanel } from './navigatormaterialspanel.js'; import { NavigatorMeshesPanel } from './navigatormeshespanel.js'; import { PanelSet } from './panelset.js'; -import { InstallVerticalSplitter } from './utils.js'; export const SelectionType = { @@ -40,10 +39,9 @@ export class Selection export class Navigator { - constructor (mainDiv, splitterDiv) + constructor (mainDiv) { this.mainDiv = mainDiv; - this.splitterDiv = splitterDiv; this.panelSet = new PanelSet (mainDiv); this.callbacks = null; @@ -60,6 +58,11 @@ export class Navigator this.panelSet.ShowPanel (this.meshesPanel); } + IsPanelsVisible () + { + return this.panelSet.IsPanelsVisible (); + } + ShowPanels (show) { this.panelSet.ShowPanels (show); @@ -71,12 +74,11 @@ export class Navigator this.panelSet.Init ({ onResizeRequested : () => { - ShowDomElement (this.splitterDiv, this.panelSet.IsPanelsVisible ()); this.callbacks.onResizeRequested (); }, onShowHidePanels : (show) => { this.callbacks.onShowHidePanels (show); - }, + } }); this.filesPanel.Init ({ @@ -121,26 +123,21 @@ export class Navigator this.SetSelection (null); } }); - - InstallVerticalSplitter (this.splitterDiv, this.mainDiv, false, () => { - this.callbacks.onResizeRequested (); - }); } GetWidth () { - let navigatorWidth = GetDomElementOuterWidth (this.mainDiv); - let splitterWidth = 0; - if (this.panelSet.IsPanelsVisible ()) { - splitterWidth = this.splitterDiv.offsetWidth; - } - return navigatorWidth + splitterWidth; + return GetDomElementOuterWidth (this.mainDiv); + } + + SetWidth (width) + { + SetDomElementOuterWidth (this.mainDiv, width); } Resize (height) { SetDomElementOuterHeight (this.mainDiv, height); - SetDomElementHeight (this.splitterDiv, height); this.panelSet.Resize (); } diff --git a/source/website/sidebar.js b/source/website/sidebar.js index 858b802..cbc4814 100644 --- a/source/website/sidebar.js +++ b/source/website/sidebar.js @@ -1,15 +1,13 @@ -import { ShowDomElement, SetDomElementWidth, SetDomElementHeight, GetDomElementOuterWidth, SetDomElementOuterHeight } from '../engine/viewer/domutils.js'; +import { GetDomElementOuterWidth, SetDomElementOuterHeight, SetDomElementOuterWidth } from '../engine/viewer/domutils.js'; import { PanelSet } from './panelset.js'; import { SidebarDetailsPanel } from './sidebardetailspanel.js'; import { SidebarSettingsPanel } from './sidebarsettingspanel.js'; -import { InstallVerticalSplitter } from './utils.js'; export class Sidebar { - constructor (mainDiv, splitterDiv, settings) + constructor (mainDiv, settings) { this.mainDiv = mainDiv; - this.splitterDiv = splitterDiv; this.panelSet = new PanelSet (mainDiv); this.detailsPanel = new SidebarDetailsPanel (this.panelSet.GetContentDiv ()); @@ -25,6 +23,11 @@ export class Sidebar return this.panelSet.IsPanelsVisible (); } + IsPanelsVisible () + { + return this.panelSet.IsPanelsVisible (); + } + ShowPanels (show) { this.panelSet.ShowPanels (show); @@ -36,7 +39,6 @@ export class Sidebar this.panelSet.Init ({ onResizeRequested : () => { - ShowDomElement (this.splitterDiv, this.panelSet.IsPanelsVisible ()); this.callbacks.onResizeRequested (); }, onShowHidePanels : (show) => { @@ -70,10 +72,6 @@ export class Sidebar this.callbacks.onThemeChanged (); } }); - - InstallVerticalSplitter (this.splitterDiv, this.mainDiv, true, () => { - this.callbacks.onResizeRequested (); - }); } UpdateControlsVisibility () @@ -84,24 +82,17 @@ export class Sidebar Resize (height) { SetDomElementOuterHeight (this.mainDiv, height); - SetDomElementHeight (this.splitterDiv, height); this.panelSet.Resize (); } GetWidth () { - let sidebarWidth = GetDomElementOuterWidth (this.mainDiv); - let splitterWidth = 0; - if (this.panelSet.IsPanelsVisible ()) { - splitterWidth = this.splitterDiv.offsetWidth; - } - return sidebarWidth + splitterWidth; + return GetDomElementOuterWidth (this.mainDiv); } - DecreaseWidth (diff) + SetWidth (width) { - let oldWidth = this.mainDiv.offsetWidth; - SetDomElementWidth (this.mainDiv, oldWidth - diff); + SetDomElementOuterWidth (this.mainDiv, width); } Clear () diff --git a/source/website/utils.js b/source/website/utils.js index c30675d..5b689c3 100644 --- a/source/website/utils.js +++ b/source/website/utils.js @@ -1,7 +1,6 @@ import { RGBColor, RGBColorToHexString } from '../engine/model/color.js'; import { CreateObjectUrl } from '../engine/io/bufferutils.js'; -import { AddDiv, CreateDiv, AddDomElement, GetDomElementOuterWidth, SetDomElementOuterWidth } from '../engine/viewer/domutils.js'; -import { CreateVerticalSplitter } from './splitter.js'; +import { AddDiv, CreateDiv, AddDomElement } from '../engine/viewer/domutils.js'; export function GetNameOrDefault (originalName, defaultName) { @@ -162,33 +161,6 @@ export function IsDarkTextNeededForColor (color) return intensity > 186.0; } -export function InstallVerticalSplitter (splitterDiv, resizedDiv, flipped, onResize) -{ - let originalWidth = null; - CreateVerticalSplitter (splitterDiv, { - onSplitStart : () => { - originalWidth = GetDomElementOuterWidth (resizedDiv); - }, - onSplit : (xDiff) => { - const minWidth = 280; - const maxWidth = 450; - let newWidth = 0; - if (flipped) { - newWidth = originalWidth - xDiff; - } else { - newWidth = originalWidth + xDiff; - } - if (newWidth < minWidth) { - newWidth = minWidth; - } else if (newWidth > maxWidth) { - newWidth = maxWidth; - } - SetDomElementOuterWidth (resizedDiv, newWidth); - onResize (); - } - }); -} - export function GetFilesFromDataTransfer (dataTransfer, onReady) { async function GetFileEntriesFromDirectory (dirEntry, fileEntries) diff --git a/source/website/website.js b/source/website/website.js index 996046f..abdf552 100644 --- a/source/website/website.js +++ b/source/website/website.js @@ -2,7 +2,7 @@ import { GetFileExtension, TransformFileHostUrls } from '../engine/io/fileutils. import { InputFilesFromFileObjects, InputFilesFromUrls } from '../engine/import/importerfiles.js'; import { ImportErrorCode, ImportSettings } from '../engine/import/importer.js'; import { CameraMode, Viewer } from '../engine/viewer/viewer.js'; -import { AddDiv, AddDomElement, ShowDomElement, SetDomElementOuterHeight, CreateDomElement } from '../engine/viewer/domutils.js'; +import { AddDiv, AddDomElement, ShowDomElement, SetDomElementOuterHeight, CreateDomElement, GetDomElementOuterWidth } from '../engine/viewer/domutils.js'; import { CalculatePopupPositionToScreen, ShowListPopup } from './dialogs.js'; import { HandleEvent } from './eventhandler.js'; import { HashHandler } from './hashhandler.js'; @@ -14,7 +14,7 @@ import { ThreeModelLoaderUI } from './threemodelloaderui.js'; import { Toolbar } from './toolbar.js'; import { DownloadModel, ShowExportDialog } from './exportdialog.js'; import { ShowSnapshotDialog } from './snapshotdialog.js'; -import { AddSmallWidthChangeEventListener, AddSvgIconElement, GetFilesFromDataTransfer, InstallTooltip, IsSmallWidth } from './utils.js'; +import { AddSvgIconElement, GetFilesFromDataTransfer, InstallTooltip, IsSmallWidth } from './utils.js'; import { ShowOpenUrlDialog } from './openurldialog.js'; import { ShowSharingDialog } from './sharingdialog.js'; import { HasDefaultMaterial, ReplaceDefaultMaterialColor } from '../engine/model/modelutils.js'; @@ -22,11 +22,12 @@ import { Direction } from '../engine/geometry/geometry.js'; import { CookieGetBoolVal, CookieSetBoolVal } from './cookiehandler.js'; import { MeasureTool } from './measuretool.js'; import { CloseAllDialogs } from './dialog.js'; +import { CreateVerticalSplitter } from './splitter.js'; import { EnumeratePlugins, PluginType } from './pluginregistry.js'; import * as THREE from 'three'; -export const WebsiteUIState = +const WebsiteUIState = { Undefined : 0, Intro : 1, @@ -34,6 +35,141 @@ export const WebsiteUIState = Loading : 3 }; +class WebsiteLayouter +{ + constructor (parameters, navigator, sidebar, viewer, measureTool) + { + this.parameters = parameters; + this.navigator = navigator; + this.sidebar = sidebar; + this.viewer = viewer; + this.measureTool = measureTool; + this.limits = { + minPanelWidth : 290, + minCanvasWidth : 100 + }; + } + + Init () + { + this.InstallSplitter (this.parameters.navigatorSplitterDiv, this.parameters.navigatorDiv, (originalWidth, xDiff) => { + let newWidth = originalWidth + xDiff; + this.OnSplitterDragged (newWidth - this.navigator.GetWidth (), 0); + }); + + this.InstallSplitter (this.parameters.sidebarSplitterDiv, this.parameters.sidebarDiv, (originalWidth, xDiff) => { + let newWidth = originalWidth - xDiff; + this.OnSplitterDragged (0, newWidth - this.sidebar.GetWidth ()); + }); + + this.Resize (); + } + + InstallSplitter (splitterDiv, resizedDiv, onSplit) + { + let originalWidth = null; + CreateVerticalSplitter (splitterDiv, { + onSplitStart : () => { + originalWidth = GetDomElementOuterWidth (resizedDiv); + }, + onSplit : (xDiff) => { + onSplit (originalWidth, xDiff); + } + }); + } + + OnSplitterDragged (leftDiff, rightDiff) + { + let windowWidth = window.innerWidth; + let maxPanelWidth = windowWidth - this.limits.minPanelWidth - this.limits.minCanvasWidth; + + let navigatorWidth = this.navigator.GetWidth (); + let sidebarWidth = this.sidebar.GetWidth (); + + let leftWidth = GetDomElementOuterWidth (this.parameters.leftContainerDiv); + let rightWidth = GetDomElementOuterWidth (this.parameters.rightContainerDiv); + + let newLeftWidth = leftWidth + leftDiff; + let newRightWidth = rightWidth + rightDiff; + let contentNewWidth = windowWidth - newLeftWidth - newRightWidth; + + if (newLeftWidth < this.limits.minPanelWidth) { + newLeftWidth = this.limits.minPanelWidth; + } else if (newLeftWidth > maxPanelWidth) { + newLeftWidth = maxPanelWidth; + } + + if (newRightWidth < this.limits.minPanelWidth) { + newRightWidth = this.limits.minPanelWidth; + } else if (newRightWidth > maxPanelWidth) { + newRightWidth = maxPanelWidth; + } + + if (contentNewWidth < this.limits.minCanvasWidth) { + if (leftDiff > 0) { + newLeftWidth = windowWidth - newRightWidth - this.limits.minCanvasWidth; + } else if (rightDiff > 0) { + newRightWidth = windowWidth - newLeftWidth - this.limits.minCanvasWidth; + } + } + + let newNavigatorWidth = navigatorWidth + (newLeftWidth - leftWidth); + let newSidebarWidth = sidebarWidth + (newRightWidth - rightWidth); + if (this.navigator.IsPanelsVisible ()) { + this.navigator.SetWidth (newNavigatorWidth); + } + if (this.sidebar.IsPanelsVisible ()) { + this.sidebar.SetWidth (newSidebarWidth); + } + + this.Resize (); + } + + Resize () + { + let windowWidth = window.innerWidth; + let windowHeight = window.innerHeight; + let headerHeight = this.parameters.headerDiv.offsetHeight; + + let leftWidth = 0; + let rightWidth = 0; + let safetyMargin = 0; + if (!IsSmallWidth ()) { + leftWidth = GetDomElementOuterWidth (this.parameters.leftContainerDiv); + rightWidth = GetDomElementOuterWidth (this.parameters.rightContainerDiv); + safetyMargin = 1; + } + + let contentWidth = windowWidth - leftWidth - rightWidth; + let contentHeight = windowHeight - headerHeight; + + if (contentWidth < this.limits.minCanvasWidth) { + let neededIncrease = this.limits.minCanvasWidth - contentWidth; + let navigatorPossibleDecrease = leftWidth - this.limits.minPanelWidth; + if (navigatorPossibleDecrease > neededIncrease) { + this.navigator.SetWidth (this.navigator.GetWidth () - neededIncrease); + } else { + this.navigator.SetWidth (this.navigator.GetWidth () - navigatorPossibleDecrease); + this.sidebar.SetWidth (this.sidebar.GetWidth () - (neededIncrease - navigatorPossibleDecrease)); + } + leftWidth = GetDomElementOuterWidth (this.parameters.leftContainerDiv); + rightWidth = GetDomElementOuterWidth (this.parameters.rightContainerDiv); + contentWidth = windowWidth - leftWidth - rightWidth; + } + + this.navigator.Resize (contentHeight); + SetDomElementOuterHeight (this.parameters.navigatorSplitterDiv, contentHeight); + + this.sidebar.Resize (contentHeight); + SetDomElementOuterHeight (this.parameters.sidebarSplitterDiv, contentHeight); + + SetDomElementOuterHeight (this.parameters.introDiv, contentHeight); + this.viewer.Resize (contentWidth - safetyMargin, contentHeight); + + this.measureTool.Resize (); + } +} + export class Website { constructor (parameters) @@ -44,12 +180,13 @@ export class Website this.measureTool = new MeasureTool (this.viewer, this.settings); this.hashHandler = new HashHandler (); this.toolbar = new Toolbar (this.parameters.toolbarDiv); - this.navigator = new Navigator (this.parameters.navigatorDiv, this.parameters.navigatorSplitterDiv); - this.sidebar = new Sidebar (this.parameters.sidebarDiv, this.parameters.sidebarSplitterDiv, this.settings); + this.navigator = new Navigator (this.parameters.navigatorDiv); + this.sidebar = new Sidebar (this.parameters.sidebarDiv, this.settings); this.modelLoaderUI = new ThreeModelLoaderUI (); this.themeHandler = new ThemeHandler (); this.highlightColor = new THREE.Color (0x8ec9f0); this.uiState = WebsiteUIState.Undefined; + this.layouter = new WebsiteLayouter (this.parameters, this.navigator, this.sidebar, this.viewer, this.measureTool); this.model = null; } @@ -78,58 +215,17 @@ export class Website this.viewer.SetMouseMoveHandler (this.OnModelMouseMoved.bind (this)); this.viewer.SetContextMenuHandler (this.OnModelContextMenu.bind (this)); - this.Resize (); + this.layouter.Init (); this.SetUIState (WebsiteUIState.Intro); this.hashHandler.SetEventListener (this.OnHashChange.bind (this)); this.OnHashChange (); - AddSmallWidthChangeEventListener (() => { - this.OnSmallWidthChanged (); - }); - window.addEventListener ('resize', () => { - this.Resize (); + this.layouter.Resize (); }); } - Resize () - { - let windowWidth = window.innerWidth; - let windowHeight = window.innerHeight; - let headerHeight = this.parameters.headerDiv.offsetHeight; - - let navigatorWidth = 0; - let sidebarWidth = 0; - let safetyMargin = 0; - if (!IsSmallWidth ()) { - navigatorWidth = this.navigator.GetWidth (); - sidebarWidth = this.sidebar.GetWidth (); - safetyMargin = 1; - } - - const minContentWidth = 50; - let contentWidth = windowWidth - navigatorWidth - sidebarWidth; - if (contentWidth < minContentWidth) { - this.sidebar.DecreaseWidth (minContentWidth - contentWidth); - contentWidth = minContentWidth; - } - let contentHeight = windowHeight - headerHeight; - - SetDomElementOuterHeight (this.parameters.introDiv, contentHeight); - this.navigator.Resize (contentHeight); - this.sidebar.Resize (contentHeight); - this.viewer.Resize (contentWidth - safetyMargin, contentHeight); - this.measureTool.Resize (); - } - - OnSmallWidthChanged () - { - if (this.uiState === WebsiteUIState.Model) { - this.UpdatePanelsVisibility (); - } - } - HasLoadedModel () { return this.model !== null; @@ -163,7 +259,7 @@ export class Website ShowOnlyOnModelElements (false); } - this.Resize (); + this.layouter.Resize (); } ClearModel () @@ -690,9 +786,10 @@ export class Website this.SwitchTheme (this.settings.themeId, true); }, onResizeRequested : () => { - this.Resize (); + this.layouter.Resize (); }, onShowHidePanels : (show) => { + ShowDomElement (this.parameters.sidebarSplitterDiv, show); CookieSetBoolVal ('ov_show_sidebar', show); } }); @@ -789,9 +886,10 @@ export class Website this.sidebar.AddMaterialProperties (this.model.GetMaterial (materialIndex)); }, onResizeRequested : () => { - this.Resize (); + this.layouter.Resize (); }, onShowHidePanels : (show) => { + ShowDomElement (this.parameters.navigatorSplitterDiv, show); CookieSetBoolVal ('ov_show_navigator', show); } }); diff --git a/website/css/website.css b/website/css/website.css index a47e256..c40b996 100644 --- a/website/css/website.css +++ b/website/css/website.css @@ -112,6 +112,12 @@ div.main_file_name overflow: hidden; } +div.main_left_container +{ + float: left; + overflow: auto; +} + div.main_navigator { width: 280px; @@ -133,12 +139,18 @@ div.main_viewer float: left; } +div.main_right_container +{ + float: left; + overflow: auto; +} + div.main_sidebar { width: 280px; margin: 10px 0px 10px 0px; overflow: none; - float: right; + float: left; } div.main_viewer canvas diff --git a/website/index.html b/website/index.html index 76a5ad5..24ea66d 100644 --- a/website/index.html +++ b/website/index.html @@ -68,11 +68,15 @@
- - +
+ + +
-
-
+
+
+
+