Use panel set for sidebar.

This commit is contained in:
kovacsv 2021-11-07 11:17:26 +01:00
parent 557768afe6
commit 01b09e08d0
12 changed files with 478 additions and 599 deletions

View File

@ -87,9 +87,7 @@
"website/o3dv/js/navigatoritems.js",
"website/o3dv/js/navigatorpanels.js",
"website/o3dv/js/navigator.js",
"website/o3dv/js/sidebarpanel.js",
"website/o3dv/js/detailssidebarpanel.js",
"website/o3dv/js/settingssidebarpanel.js",
"website/o3dv/js/sidebarpanels.js",
"website/o3dv/js/sidebar.js",
"website/o3dv/js/hashhandler.js",
"website/o3dv/js/loader.js",

View File

@ -110,9 +110,7 @@
<script type="text/javascript" src="o3dv/js/navigatoritems.js"></script>
<script type="text/javascript" src="o3dv/js/navigatorpanels.js"></script>
<script type="text/javascript" src="o3dv/js/navigator.js"></script>
<script type="text/javascript" src="o3dv/js/sidebarpanel.js"></script>
<script type="text/javascript" src="o3dv/js/detailssidebarpanel.js"></script>
<script type="text/javascript" src="o3dv/js/settingssidebarpanel.js"></script>
<script type="text/javascript" src="o3dv/js/sidebarpanels.js"></script>
<script type="text/javascript" src="o3dv/js/sidebar.js"></script>
<script type="text/javascript" src="o3dv/js/hashhandler.js"></script>
<script type="text/javascript" src="o3dv/js/loader.js"></script>

View File

@ -110,9 +110,7 @@
<script type="text/javascript" src="o3dv/js/navigatoritems.js"></script>
<script type="text/javascript" src="o3dv/js/navigatorpanels.js"></script>
<script type="text/javascript" src="o3dv/js/navigator.js"></script>
<script type="text/javascript" src="o3dv/js/sidebarpanel.js"></script>
<script type="text/javascript" src="o3dv/js/detailssidebarpanel.js"></script>
<script type="text/javascript" src="o3dv/js/settingssidebarpanel.js"></script>
<script type="text/javascript" src="o3dv/js/sidebarpanels.js"></script>
<script type="text/javascript" src="o3dv/js/sidebar.js"></script>
<script type="text/javascript" src="o3dv/js/hashhandler.js"></script>
<script type="text/javascript" src="o3dv/js/loader.js"></script>
@ -168,13 +166,13 @@
<div class="toolbar" id="toolbar"></div>
</div>
<div class="main" id="main">
<div class="main_navigator only_full_width" id="main_navigator">
<div class="main_navigator ov_panel_set_container only_full_width" id="main_navigator">
</div>
<div class="main_navigator_splitter only_full_width" id="main_navigator_splitter">
</div>
<div class="main_viewer" id="main_viewer">
</div>
<div class="main_sidebar only_full_width" id="main_sidebar">
<div class="main_sidebar ov_panel_set_right_container only_full_width" id="main_sidebar">
</div>
</div>
<div class="intro ov_thin_scrollbar" id="intro">

View File

@ -1,21 +1,33 @@
div.ov_panel_set_menu
div.ov_panel_set_container div.ov_panel_set_menu
{
float: left;
}
div.ov_panel_set_right_container div.ov_panel_set_menu
{
float: right;
}
div.ov_panel_set_menu div.ov_panel_set_menu_button
{
padding: 6px;
cursor: pointer;
}
div.ov_panel_set_content
div.ov_panel_set_container div.ov_panel_set_content
{
padding-left: 10px;
border-left: 1px solid var(--ov_border_color);
overflow: auto;
}
div.ov_panel_set_right_container div.ov_panel_set_content
{
padding-right: 10px;
border-right: 1px solid var(--ov_border_color);
overflow: auto;
}
@media (hover)
{

View File

@ -125,14 +125,14 @@ div.main_viewer
div.main_sidebar
{
width: 300px;
margin: 10px 10px 10px 0px;
margin: 10px 0px 10px 10px;
overflow: none;
float: right;
}
div.main_viewer canvas
{
margin: 10px 10px 10px 0px;
margin: 10px 0px 10px 0px;
border: 1px solid var(--ov_border_color);
outline: none;
display: block;

View File

@ -1,159 +0,0 @@
OV.DetailsSidebarPanel = class extends OV.SidebarPanel
{
constructor (parentDiv)
{
super (parentDiv);
}
GetTitle ()
{
return 'Details';
}
AddObject3DProperties (object3D)
{
this.Clear ();
let table = $('<div>').addClass ('ov_property_table').appendTo (this.contentDiv);
let boundingBox = OV.GetBoundingBox (object3D);
let size = OV.SubCoord3D (boundingBox.max, boundingBox.min);
this.AddProperty (table, new OV.Property (OV.PropertyType.Integer, 'Vertex Count', object3D.VertexCount ()));
this.AddProperty (table, new OV.Property (OV.PropertyType.Integer, 'Triangle Count', object3D.TriangleCount ()));
this.AddProperty (table, new OV.Property (OV.PropertyType.Number, 'Size X', size.x));
this.AddProperty (table, new OV.Property (OV.PropertyType.Number, 'Size Y', size.y));
this.AddProperty (table, new OV.Property (OV.PropertyType.Number, 'Size Z', size.z));
this.AddCalculatedProperty (table, 'Volume', () => {
const volume = OV.CalculateVolume (object3D);
if (volume === null) {
return null;
}
return new OV.Property (OV.PropertyType.Number, null, volume);
});
this.AddCalculatedProperty (table, 'Surface Area', () => {
const volume = OV.CalculateSurfaceArea (object3D);
if (volume === null) {
return null;
}
return new OV.Property (OV.PropertyType.Number, null, volume);
});
if (object3D.PropertyGroupCount () > 0) {
let customTable = $('<div>').addClass ('ov_property_table ov_property_table_custom').appendTo (this.contentDiv);
for (let i = 0; i < object3D.PropertyGroupCount (); i++) {
const propertyGroup = object3D.GetPropertyGroup (i);
this.AddPropertyGroup (customTable, propertyGroup);
for (let j = 0; j < propertyGroup.PropertyCount (); j++) {
const property = propertyGroup.GetProperty (j);
this.AddPropertyInGroup (customTable, property);
}
}
}
this.Resize ();
}
AddMaterialProperties (material)
{
function AddTextureMap (obj, table, name, map)
{
if (map === null || map.name === null) {
return;
}
let fileName = OV.GetFileName (map.name);
obj.AddProperty (table, new OV.Property (OV.PropertyType.Text, name, fileName));
}
this.Clear ();
let table = $('<div>').addClass ('ov_property_table').appendTo (this.contentDiv);
let typeString = null;
if (material.type === OV.MaterialType.Phong) {
typeString = 'Phong';
} else if (material.type === OV.MaterialType.Physical) {
typeString = 'Physical';
}
this.AddProperty (table, new OV.Property (OV.PropertyType.Text, 'Source', material.isDefault ? 'Default' : 'Model'));
this.AddProperty (table, new OV.Property (OV.PropertyType.Text, 'Type', typeString));
this.AddProperty (table, new OV.Property (OV.PropertyType.Color, 'Color', material.color));
if (material.type === OV.MaterialType.Physical) {
this.AddProperty (table, new OV.Property (OV.PropertyType.Percent, 'Metalness', material.metalness));
this.AddProperty (table, new OV.Property (OV.PropertyType.Percent, 'Roughness', material.roughness));
}
this.AddProperty (table, new OV.Property (OV.PropertyType.Percent, 'Opacity', material.opacity));
AddTextureMap (this, table, 'Diffuse Map', material.diffuseMap);
AddTextureMap (this, table, 'Specular Map', material.specularMap);
AddTextureMap (this, table, 'Bump Map', material.bumpMap);
AddTextureMap (this, table, 'Normal Map', material.normalMap);
AddTextureMap (this, table, 'Emissive Map', material.emissiveMap);
AddTextureMap (this, table, 'Metallic Map', material.metalnessMap);
this.Resize ();
}
AddPropertyGroup (table, propertyGroup)
{
let row = $('<div>').addClass ('ov_property_table_row group').appendTo (table);
row.html (propertyGroup.name).attr ('title', propertyGroup.name);
}
AddProperty (table, property)
{
let row = $('<div>').addClass ('ov_property_table_row').appendTo (table);
let nameColum = $('<div>').addClass ('ov_property_table_cell ov_property_table_name').appendTo (row);
let valueColumn = $('<div>').addClass ('ov_property_table_cell ov_property_table_value').appendTo (row);
nameColum.html (property.name + ':').attr ('title', property.name);
this.DisplayPropertyValue (property, valueColumn);
return row;
}
AddPropertyInGroup (table, property)
{
let row = this.AddProperty (table, property);
row.addClass ('ingroup');
}
AddCalculatedProperty (table, name, calculateValue)
{
let row = $('<div>').addClass ('ov_property_table_row').appendTo (table);
let nameColum = $('<div>').addClass ('ov_property_table_cell ov_property_table_name').appendTo (row);
let valueColumn = $('<div>').addClass ('ov_property_table_cell ov_property_table_value').appendTo (row);
nameColum.html (name + ':').attr ('title', name);
let calculateButton = $('<div>').addClass ('ov_property_table_button').html ('Calculate...').appendTo (valueColumn);
calculateButton.click (() => {
valueColumn.empty ();
valueColumn.html ('Please wait...');
OV.RunTaskAsync (() => {
let propertyValue = calculateValue ();
if (propertyValue === null) {
valueColumn.html ('-');
} else {
this.DisplayPropertyValue (propertyValue, valueColumn);
}
});
});
}
DisplayPropertyValue (property, targetDiv)
{
targetDiv.empty ();
let valueText = null;
if (property.type === OV.PropertyType.Text) {
valueText = property.value;
} else if (property.type === OV.PropertyType.Integer) {
valueText = property.value.toLocaleString ();
} else if (property.type === OV.PropertyType.Number) {
valueText = property.value.toLocaleString (undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
} else if (property.type === OV.PropertyType.Boolean) {
valueText = property.value ? 'True' : 'False';
} else if (property.type === OV.PropertyType.Percent) {
valueText = parseInt (property.value * 100, 10).toString () + '%';
} else if (property.type === OV.PropertyType.Color) {
let hexString = '#' + OV.ColorToHexString (property.value);
let colorCircle = OV.CreateInlineColorCircle (property.value);
colorCircle.appendTo (targetDiv);
$('<span>').html (hexString).appendTo (targetDiv);
}
if (valueText !== null) {
targetDiv.html (valueText).attr ('title', valueText);
}
}
};

View File

@ -149,11 +149,13 @@ OV.NavigatorPanel = class extends OV.Panel
this.titleDiv = $('<div>').addClass ('ov_navigator_tree_title').appendTo (this.panelDiv);
this.treeDiv = $('<div>').addClass ('ov_navigator_tree_panel').addClass ('ov_thin_scrollbar').appendTo (this.panelDiv);
this.treeView = new OV.TreeView (this.treeDiv);
let panelName = this.GetName ();
this.titleDiv.html (panelName).attr ('title', panelName);
}
Clear ()
{
this.titleDiv.empty ();
this.treeView.Clear ();
}
@ -169,8 +171,7 @@ OV.NavigatorPanel = class extends OV.Panel
Fill (importResult)
{
let panelName = this.GetName ();
this.titleDiv.html (panelName).attr ('title', panelName);
}
};
@ -181,6 +182,11 @@ OV.NavigatorFilesPanel = class extends OV.NavigatorPanel
super (parentDiv);
}
GetName ()
{
return 'Files';
}
GetIcon ()
{
return 'files';
@ -198,11 +204,6 @@ OV.NavigatorFilesPanel = class extends OV.NavigatorPanel
super.Clear ();
}
GetName ()
{
return 'Files';
}
Fill (importResult)
{
super.Fill (importResult);
@ -248,6 +249,11 @@ OV.NavigatorMaterialsPanel = class extends OV.NavigatorPanel
this.meshesButton = new OV.NavigatorMeshesPopupButton (this.popupDiv);
}
GetName ()
{
return 'Materials';
}
GetIcon ()
{
return 'materials';
@ -268,11 +274,6 @@ OV.NavigatorMaterialsPanel = class extends OV.NavigatorPanel
this.materialIndexToItem = new Map ();
}
GetName ()
{
return 'Materials';
}
Init (callbacks)
{
super.Init (callbacks);
@ -333,6 +334,11 @@ OV.NavigatorMeshesPanel = class extends OV.NavigatorPanel
this.materialsButton = new OV.NavigatorMaterialsPopupButton (this.popupDiv);
}
GetName ()
{
return 'Meshes';
}
GetIcon ()
{
return 'meshes';
@ -370,11 +376,6 @@ OV.NavigatorMeshesPanel = class extends OV.NavigatorPanel
});
}
GetName ()
{
return 'Meshes';
}
Fill (importResult)
{
super.Fill (importResult);
@ -542,40 +543,4 @@ OV.NavigatorMeshesPanel = class extends OV.NavigatorPanel
return true;
});
}
UpdatePopupButton ()
{
// if (this.selection === null) {
// let usedMaterials = this.callbacks.getMaterialsForModel ();
// this.popupButton.FillWithModelInfo (usedMaterials, {
// onMaterialSelect : (materialIndex) => {
// this.SetSelection (new OV.Selection (OV.SelectionType.Material, materialIndex));
// }
// });
// this.callbacks.onModelSelected ();
// } else {
// if (this.selection.type === OV.SelectionType.Material) {
// let usedByMeshes = this.callbacks.getMeshesForMaterial (this.selection.materialIndex);
// this.popupButton.FillWithMaterialInfo (usedByMeshes, {
// onMeshHover : (meshInstanceId) => {
// this.tempSelectedMeshId = meshInstanceId;
// this.callbacks.updateMeshesSelection ();
// },
// onMeshSelect : (meshInstanceId) => {
// this.SetSelection (new OV.Selection (OV.SelectionType.Mesh, meshInstanceId));
// }
// });
// this.callbacks.onMaterialSelected (this.selection.materialIndex);
// } else if (this.selection.type === OV.SelectionType.Mesh) {
// let usedMaterials = this.callbacks.getMaterialsForMesh (this.selection.meshInstanceId);
// this.popupButton.FillWithModelInfo (usedMaterials, {
// onMaterialSelect : (materialIndex) => {
// this.SetSelection (new OV.Selection (OV.SelectionType.Material, materialIndex));
// }
// });
// this.callbacks.onMeshSelected (this.selection.meshInstanceId);
// }
// }
// this.Resize ();
}
};

View File

@ -1,167 +0,0 @@
OV.SettingsSidebarPanel = class extends OV.SidebarPanel
{
constructor (parentDiv)
{
super (parentDiv);
this.backgroundColorInput = null;
this.defaultColorInput = null;
this.defaultColorWarning = null;
this.themeInput = null;
}
GetTitle ()
{
return 'Settings';
}
HidePopups ()
{
this.backgroundColorInput.pickr.hide ();
this.defaultColorInput.pickr.hide ();
}
InitSettings (settings, defaultSettings, callbacks)
{
this.backgroundColorInput = this.AddColorParameter (
'Background Color',
'Background color affects only the visualization of the model.',
null,
['#ffffff', '#e3e3e3', '#c9c9c9', '#898989', '#5f5f5f', '#494949', '#383838', '#0f0f0f'],
settings.backgroundColor,
callbacks.onBackgroundColorChange
);
this.defaultColorInput = this.AddColorParameter (
'Default Color',
'Default color appears when the model doesn\'t contain materials.',
'This setting has no effect on the currently loaded file.',
['#ffffff', '#e3e3e3', '#cc3333', '#fac832', '#4caf50', '#3393bd', '#9b27b0', '#fda4b8'],
settings.defaultColor,
callbacks.onDefaultColorChange
);
this.themeInput = this.AddThemeParameter (settings.themeId, callbacks.onThemeChange);
this.AddResetToDefaultsButton (defaultSettings, callbacks);
}
UpdateSettings (settings)
{
this.backgroundColorInput.pickr.setColor ('#' + OV.ColorToHexString (settings.backgroundColor));
this.defaultColorInput.pickr.setColor ('#' + OV.ColorToHexString (settings.defaultColor));
}
Update (model)
{
let hasDefaultMaterial = OV.HasDefaultMaterial (model);
if (!hasDefaultMaterial) {
this.defaultColorInput.warning.show ();
} else {
this.defaultColorInput.warning.hide ();
}
this.Resize ();
}
AddColorParameter (title, description, warningText, predefinedColors, defaultValue, onChange)
{
let contentDiv = $('<div>').addClass ('ov_sidebar_settings_content').appendTo (this.contentDiv);
let titleDiv = $('<div>').addClass ('ov_sidebar_subtitle').appendTo (contentDiv);
let colorInput = $('<div>').addClass ('color-picker').appendTo (titleDiv);
$('<span>').html (title).appendTo (titleDiv);
const pickr = Pickr.create ({
el : colorInput.get (0),
theme : 'monolith',
position : 'left-start',
swatches : predefinedColors,
comparison : false,
default : '#' + OV.ColorToHexString (defaultValue),
components : {
preview : false,
opacity : false,
hue : true,
interaction: {
hex : false,
rgba : false,
hsla : false,
hsva : false,
cmyk : false,
input : true,
clear : false,
save : false
}
}
});
pickr.on ('change', (color, source, instance) => {
let rgbaColor = color.toRGBA ();
let ovColor = new OV.Color (
parseInt (rgbaColor[0], 10),
parseInt (rgbaColor[1], 10),
parseInt (rgbaColor[2], 10)
);
onChange (ovColor);
});
$('<div>').addClass ('ov_sidebar_settings_padded').html (description).appendTo (contentDiv);
let warningDiv = null;
if (warningText !== null) {
warningDiv = $('<div>').addClass ('ov_sidebar_settings_padded').appendTo (contentDiv);
OV.AddSvgIcon (warningDiv, 'warning', 'left_inline light');
$('<div>').addClass ('ov_sidebar_settings_warning').html (warningText).appendTo (warningDiv);
}
return {
pickr : pickr,
warning : warningDiv
};
}
AddThemeParameter (defaultValue, onChange)
{
function AddRadioButton (contentDiv, themeId, themeName, onChange)
{
let row = $('<div>').addClass ('ov_sidebar_settings_row').appendTo (contentDiv);
let label = $('<label>').attr ('for', themeId.toString ()).appendTo (row);
let radio = $('<input>').addClass ('ov_radio_button').attr ('type', 'radio').attr ('id', themeId.toString ()).attr ('name', 'theme').appendTo (label);
$('<span>').html (themeName).appendTo (label);
radio.change (() => {
onChange (themeId);
});
return radio;
}
function Select (radioButtons, defaultValue)
{
for (let i = 0; i < radioButtons.length; i++) {
let radioButton = radioButtons[i];
radioButton.prop ('checked', radioButton.attr ('id') === defaultValue.toString ());
}
}
let contentDiv = $('<div>').addClass ('ov_sidebar_settings_content').appendTo (this.contentDiv);
let titleDiv = $('<div>').addClass ('ov_sidebar_subtitle').appendTo (contentDiv);
OV.AddSvgIcon (titleDiv, 'theme', 'ov_sidebar_subtitle_icon');
$('<div>').html ('Appearance').appendTo (titleDiv);
let buttonsDiv = $('<div>').addClass ('ov_sidebar_settings_padded').appendTo (contentDiv);
let result = {
buttons : [],
select: (value) => {
Select (result.buttons, value);
}
};
result.buttons.push (AddRadioButton (buttonsDiv, OV.Theme.Light, 'Light', onChange));
result.buttons.push (AddRadioButton (buttonsDiv, OV.Theme.Dark, 'Dark', onChange));
Select (result.buttons, defaultValue);
return result;
}
AddResetToDefaultsButton (defaultSettings, callbacks)
{
let resetToDefaultsButton = $('<div>').addClass ('ov_button').addClass ('outline').addClass ('ov_sidebar_button').html ('Reset to Default').appendTo (this.contentDiv);
resetToDefaultsButton.click (() => {
this.backgroundColorInput.pickr.setColor ('#' + OV.ColorToHexString (defaultSettings.backgroundColor));
callbacks.onBackgroundColorChange (defaultSettings.backgroundColor);
this.defaultColorInput.pickr.setColor ('#' + OV.ColorToHexString (defaultSettings.defaultColor));
callbacks.onDefaultColorChange (defaultSettings.defaultColor);
if (this.themeInput !== null) {
this.themeInput.select (defaultSettings.themeId);
callbacks.onThemeChange (defaultSettings.themeId);
}
});
}
};

View File

@ -1,73 +1,86 @@
OV.Sidebar = class
{
constructor (parentDiv)
constructor (mainDiv)
{
this.parentDiv = parentDiv;
this.visible = true;
this.titleDiv = null;
this.contentDiv = null;
this.panels = [];
this.mainDiv = mainDiv;
this.panelSet = new OV.PanelSet (mainDiv);
this.detailsPanel = new OV.DetailsSidebarPanel (this.panelSet.GetContentDiv ());
this.settingsPanel = new OV.SettingsSidebarPanel (this.panelSet.GetContentDiv ());
this.panelSet.AddPanel (this.detailsPanel);
this.panelSet.AddPanel (this.settingsPanel);
this.panelSet.ShowPanel (this.detailsPanel);
}
AddPanel (panel)
Init (settings, callbacks)
{
this.panels.push (panel);
return this.panels.length - 1;
}
this.callbacks = callbacks;
GetPanel (id)
{
return this.panels[id];
}
Show (panelId)
{
if (panelId !== null) {
this.visible = true;
this.parentDiv.show ();
for (let id = 0; id < this.panels.length; id++) {
let panel = this.panels[id];
if (id === panelId) {
panel.Show (true);
this.panelSet.Init ({
onResize : () => {
if (this.panelSet.IsPanelsVisible ()) {
//this.splitterDiv.show ();
} else {
panel.Show (false);
//this.splitterDiv.hide ();
}
this.callbacks.onResize ();
}
});
let defaultSettings = new OV.Settings ();
this.settingsPanel.InitSettings (
settings,
defaultSettings,
{
onBackgroundColorChange : (newVal) => {
this.callbacks.onBackgroundColorChange (newVal);
},
onDefaultColorChange : (newVal) => {
this.callbacks.onDefaultColorChange (newVal);
},
onThemeChange : (newVal) => {
this.callbacks.onThemeChange (newVal);
}
}
} else {
this.visible = false;
this.parentDiv.hide ();
}
);
}
IsVisible ()
Update (model)
{
return this.visible;
this.settingsPanel.Update (model);
}
GetVisiblePanelId ()
Resize (height)
{
if (!this.visible) {
return null;
}
for (let id = 0; id < this.panels.length; id++) {
if (this.panels[id].IsVisible ()) {
return id;
}
}
return null;
this.mainDiv.outerHeight (height, true);
//this.splitterDiv.outerHeight (height, true);
this.panelSet.Resize ();
}
HidePopups ()
GetWidth ()
{
for (let id = 0; id < this.panels.length; id++) {
this.panels[id].HidePopups ();
}
let sidebarWidth = parseInt (this.mainDiv.outerWidth (true), 10);
// let splitterWidth = 0;
// if (this.panelSet.IsPanelsVisible ()) {
// splitterWidth = parseInt (this.splitterDiv.outerWidth (true), 10);
// }
//return sidebarWidth + splitterWidth;
return sidebarWidth;
}
Resize ()
Clear ()
{
for (let id = 0; id < this.panels.length; id++) {
this.panels[id].Resize ();
}
this.panelSet.Clear ();
}
AddObject3DProperties (object3D)
{
this.detailsPanel.AddObject3DProperties (object3D);
}
AddMaterialProperties (material)
{
this.detailsPanel.AddMaterialProperties (material);
}
};

View File

@ -1,59 +0,0 @@
OV.SidebarPanel = class
{
constructor (parentDiv)
{
this.parentDiv = parentDiv;
this.panelDiv = $('<div>').appendTo (this.parentDiv).hide ();
this.titleDiv = null;
this.contentDiv = null;
this.visible = false;
}
Init (callbacks)
{
this.titleDiv = $('<div>').addClass ('ov_sidebar_title').appendTo (this.panelDiv);
this.contentDiv = $('<div>').addClass ('ov_sidebar_content').addClass ('ov_thin_scrollbar').appendTo (this.panelDiv);
$('<div>').addClass ('ov_sidebar_title_text').html (this.GetTitle ()).appendTo (this.titleDiv);
let titleImg = OV.AddSvgIcon (this.titleDiv, 'close', 'ov_sidebar_title_img');
titleImg.click (() => {
callbacks.onClose ();
});
}
GetTitle ()
{
return '';
}
Show (show)
{
this.visible = show;
if (this.visible) {
this.panelDiv.show ();
} else {
this.panelDiv.hide ();
}
}
IsVisible ()
{
return this.visible;
}
Resize ()
{
let titleHeight = this.titleDiv.outerHeight (true);
let height = this.parentDiv.height ();
this.contentDiv.outerHeight (height - titleHeight, true);
}
Clear ()
{
this.contentDiv.empty ();
}
HidePopups ()
{
}
};

View File

@ -0,0 +1,364 @@
OV.SidebarPanel = class extends OV.Panel
{
constructor (parentDiv)
{
super (parentDiv);
this.callbacks = null;
this.titleDiv = $('<div>').addClass ('ov_sidebar_title').appendTo (this.panelDiv);
this.contentDiv = $('<div>').addClass ('ov_sidebar_content').addClass ('ov_thin_scrollbar').appendTo (this.panelDiv);
$('<div>').addClass ('ov_sidebar_title_text').html (this.GetName ()).appendTo (this.titleDiv);
let panelName = this.GetName ();
this.titleDiv.html (panelName).attr ('title', panelName);
}
GetName ()
{
return null;
}
Clear ()
{
this.contentDiv.empty ();
}
Init (callbacks)
{
this.callbacks = callbacks;
}
};
OV.DetailsSidebarPanel = class extends OV.SidebarPanel
{
constructor (parentDiv)
{
super (parentDiv);
}
GetName ()
{
return 'Details';
}
GetIcon ()
{
return 'details';
}
AddObject3DProperties (object3D)
{
this.Clear ();
let table = $('<div>').addClass ('ov_property_table').appendTo (this.contentDiv);
let boundingBox = OV.GetBoundingBox (object3D);
let size = OV.SubCoord3D (boundingBox.max, boundingBox.min);
this.AddProperty (table, new OV.Property (OV.PropertyType.Integer, 'Vertex Count', object3D.VertexCount ()));
this.AddProperty (table, new OV.Property (OV.PropertyType.Integer, 'Triangle Count', object3D.TriangleCount ()));
this.AddProperty (table, new OV.Property (OV.PropertyType.Number, 'Size X', size.x));
this.AddProperty (table, new OV.Property (OV.PropertyType.Number, 'Size Y', size.y));
this.AddProperty (table, new OV.Property (OV.PropertyType.Number, 'Size Z', size.z));
this.AddCalculatedProperty (table, 'Volume', () => {
const volume = OV.CalculateVolume (object3D);
if (volume === null) {
return null;
}
return new OV.Property (OV.PropertyType.Number, null, volume);
});
this.AddCalculatedProperty (table, 'Surface Area', () => {
const volume = OV.CalculateSurfaceArea (object3D);
if (volume === null) {
return null;
}
return new OV.Property (OV.PropertyType.Number, null, volume);
});
if (object3D.PropertyGroupCount () > 0) {
let customTable = $('<div>').addClass ('ov_property_table ov_property_table_custom').appendTo (this.contentDiv);
for (let i = 0; i < object3D.PropertyGroupCount (); i++) {
const propertyGroup = object3D.GetPropertyGroup (i);
this.AddPropertyGroup (customTable, propertyGroup);
for (let j = 0; j < propertyGroup.PropertyCount (); j++) {
const property = propertyGroup.GetProperty (j);
this.AddPropertyInGroup (customTable, property);
}
}
}
this.Resize ();
}
AddMaterialProperties (material)
{
function AddTextureMap (obj, table, name, map)
{
if (map === null || map.name === null) {
return;
}
let fileName = OV.GetFileName (map.name);
obj.AddProperty (table, new OV.Property (OV.PropertyType.Text, name, fileName));
}
this.Clear ();
let table = $('<div>').addClass ('ov_property_table').appendTo (this.contentDiv);
let typeString = null;
if (material.type === OV.MaterialType.Phong) {
typeString = 'Phong';
} else if (material.type === OV.MaterialType.Physical) {
typeString = 'Physical';
}
this.AddProperty (table, new OV.Property (OV.PropertyType.Text, 'Source', material.isDefault ? 'Default' : 'Model'));
this.AddProperty (table, new OV.Property (OV.PropertyType.Text, 'Type', typeString));
this.AddProperty (table, new OV.Property (OV.PropertyType.Color, 'Color', material.color));
if (material.type === OV.MaterialType.Physical) {
this.AddProperty (table, new OV.Property (OV.PropertyType.Percent, 'Metalness', material.metalness));
this.AddProperty (table, new OV.Property (OV.PropertyType.Percent, 'Roughness', material.roughness));
}
this.AddProperty (table, new OV.Property (OV.PropertyType.Percent, 'Opacity', material.opacity));
AddTextureMap (this, table, 'Diffuse Map', material.diffuseMap);
AddTextureMap (this, table, 'Specular Map', material.specularMap);
AddTextureMap (this, table, 'Bump Map', material.bumpMap);
AddTextureMap (this, table, 'Normal Map', material.normalMap);
AddTextureMap (this, table, 'Emissive Map', material.emissiveMap);
AddTextureMap (this, table, 'Metallic Map', material.metalnessMap);
this.Resize ();
}
AddPropertyGroup (table, propertyGroup)
{
let row = $('<div>').addClass ('ov_property_table_row group').appendTo (table);
row.html (propertyGroup.name).attr ('title', propertyGroup.name);
}
AddProperty (table, property)
{
let row = $('<div>').addClass ('ov_property_table_row').appendTo (table);
let nameColum = $('<div>').addClass ('ov_property_table_cell ov_property_table_name').appendTo (row);
let valueColumn = $('<div>').addClass ('ov_property_table_cell ov_property_table_value').appendTo (row);
nameColum.html (property.name + ':').attr ('title', property.name);
this.DisplayPropertyValue (property, valueColumn);
return row;
}
AddPropertyInGroup (table, property)
{
let row = this.AddProperty (table, property);
row.addClass ('ingroup');
}
AddCalculatedProperty (table, name, calculateValue)
{
let row = $('<div>').addClass ('ov_property_table_row').appendTo (table);
let nameColum = $('<div>').addClass ('ov_property_table_cell ov_property_table_name').appendTo (row);
let valueColumn = $('<div>').addClass ('ov_property_table_cell ov_property_table_value').appendTo (row);
nameColum.html (name + ':').attr ('title', name);
let calculateButton = $('<div>').addClass ('ov_property_table_button').html ('Calculate...').appendTo (valueColumn);
calculateButton.click (() => {
valueColumn.empty ();
valueColumn.html ('Please wait...');
OV.RunTaskAsync (() => {
let propertyValue = calculateValue ();
if (propertyValue === null) {
valueColumn.html ('-');
} else {
this.DisplayPropertyValue (propertyValue, valueColumn);
}
});
});
}
DisplayPropertyValue (property, targetDiv)
{
targetDiv.empty ();
let valueText = null;
if (property.type === OV.PropertyType.Text) {
valueText = property.value;
} else if (property.type === OV.PropertyType.Integer) {
valueText = property.value.toLocaleString ();
} else if (property.type === OV.PropertyType.Number) {
valueText = property.value.toLocaleString (undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
} else if (property.type === OV.PropertyType.Boolean) {
valueText = property.value ? 'True' : 'False';
} else if (property.type === OV.PropertyType.Percent) {
valueText = parseInt (property.value * 100, 10).toString () + '%';
} else if (property.type === OV.PropertyType.Color) {
let hexString = '#' + OV.ColorToHexString (property.value);
let colorCircle = OV.CreateInlineColorCircle (property.value);
colorCircle.appendTo (targetDiv);
$('<span>').html (hexString).appendTo (targetDiv);
}
if (valueText !== null) {
targetDiv.html (valueText).attr ('title', valueText);
}
}
};
OV.SettingsSidebarPanel = class extends OV.SidebarPanel
{
constructor (parentDiv)
{
super (parentDiv);
this.backgroundColorInput = null;
this.defaultColorInput = null;
this.defaultColorWarning = null;
this.themeInput = null;
}
GetName ()
{
return 'Settings';
}
GetIcon ()
{
return 'settings';
}
Clear ()
{
this.backgroundColorInput.pickr.hide ();
this.defaultColorInput.pickr.hide ();
}
InitSettings (settings, defaultSettings, callbacks)
{
this.Init (callbacks);
this.backgroundColorInput = this.AddColorParameter (
'Background Color',
'Background color affects only the visualization of the model.',
null,
['#ffffff', '#e3e3e3', '#c9c9c9', '#898989', '#5f5f5f', '#494949', '#383838', '#0f0f0f'],
settings.backgroundColor,
this.callbacks.onBackgroundColorChange
);
this.defaultColorInput = this.AddColorParameter (
'Default Color',
'Default color appears when the model doesn\'t contain materials.',
'This setting has no effect on the currently loaded file.',
['#ffffff', '#e3e3e3', '#cc3333', '#fac832', '#4caf50', '#3393bd', '#9b27b0', '#fda4b8'],
settings.defaultColor,
this.callbacks.onDefaultColorChange
);
this.themeInput = this.AddThemeParameter (settings.themeId);
this.AddResetToDefaultsButton (defaultSettings);
}
Update (model)
{
let hasDefaultMaterial = OV.HasDefaultMaterial (model);
if (!hasDefaultMaterial) {
this.defaultColorInput.warning.show ();
} else {
this.defaultColorInput.warning.hide ();
}
this.Resize ();
}
AddColorParameter (title, description, warningText, predefinedColors, defaultValue, onChange)
{
let contentDiv = $('<div>').addClass ('ov_sidebar_settings_content').appendTo (this.contentDiv);
let titleDiv = $('<div>').addClass ('ov_sidebar_subtitle').appendTo (contentDiv);
let colorInput = $('<div>').addClass ('color-picker').appendTo (titleDiv);
$('<span>').html (title).appendTo (titleDiv);
const pickr = Pickr.create ({
el : colorInput.get (0),
theme : 'monolith',
position : 'left-start',
swatches : predefinedColors,
comparison : false,
default : '#' + OV.ColorToHexString (defaultValue),
components : {
preview : false,
opacity : false,
hue : true,
interaction: {
hex : false,
rgba : false,
hsla : false,
hsva : false,
cmyk : false,
input : true,
clear : false,
save : false
}
}
});
pickr.on ('change', (color, source, instance) => {
let rgbaColor = color.toRGBA ();
let ovColor = new OV.Color (
parseInt (rgbaColor[0], 10),
parseInt (rgbaColor[1], 10),
parseInt (rgbaColor[2], 10)
);
onChange (ovColor);
});
$('<div>').addClass ('ov_sidebar_settings_padded').html (description).appendTo (contentDiv);
let warningDiv = null;
if (warningText !== null) {
warningDiv = $('<div>').addClass ('ov_sidebar_settings_padded').appendTo (contentDiv);
OV.AddSvgIcon (warningDiv, 'warning', 'left_inline light');
$('<div>').addClass ('ov_sidebar_settings_warning').html (warningText).appendTo (warningDiv);
}
return {
pickr : pickr,
warning : warningDiv
};
}
AddThemeParameter (defaultValue)
{
function AddRadioButton (contentDiv, themeId, themeName, onChange)
{
let row = $('<div>').addClass ('ov_sidebar_settings_row').appendTo (contentDiv);
let label = $('<label>').attr ('for', themeId.toString ()).appendTo (row);
let radio = $('<input>').addClass ('ov_radio_button').attr ('type', 'radio').attr ('id', themeId.toString ()).attr ('name', 'theme').appendTo (label);
$('<span>').html (themeName).appendTo (label);
radio.change (() => {
onChange (themeId);
});
return radio;
}
function Select (radioButtons, defaultValue)
{
for (let i = 0; i < radioButtons.length; i++) {
let radioButton = radioButtons[i];
radioButton.prop ('checked', radioButton.attr ('id') === defaultValue.toString ());
}
}
let contentDiv = $('<div>').addClass ('ov_sidebar_settings_content').appendTo (this.contentDiv);
let titleDiv = $('<div>').addClass ('ov_sidebar_subtitle').appendTo (contentDiv);
OV.AddSvgIcon (titleDiv, 'theme', 'ov_sidebar_subtitle_icon');
$('<div>').html ('Appearance').appendTo (titleDiv);
let buttonsDiv = $('<div>').addClass ('ov_sidebar_settings_padded').appendTo (contentDiv);
let result = {
buttons : [],
select: (value) => {
Select (result.buttons, value);
}
};
result.buttons.push (AddRadioButton (buttonsDiv, OV.Theme.Light, 'Light', this.callbacks.onThemeChange));
result.buttons.push (AddRadioButton (buttonsDiv, OV.Theme.Dark, 'Dark', this.callbacks.onThemeChange));
Select (result.buttons, defaultValue);
return result;
}
AddResetToDefaultsButton (defaultSettings)
{
let resetToDefaultsButton = $('<div>').addClass ('ov_button').addClass ('outline').addClass ('ov_sidebar_button').html ('Reset to Default').appendTo (this.contentDiv);
resetToDefaultsButton.click (() => {
this.backgroundColorInput.pickr.setColor ('#' + OV.ColorToHexString (defaultSettings.backgroundColor));
this.callbacks.onBackgroundColorChange (defaultSettings.backgroundColor);
this.defaultColorInput.pickr.setColor ('#' + OV.ColorToHexString (defaultSettings.defaultColor));
this.callbacks.onDefaultColorChange (defaultSettings.defaultColor);
if (this.themeInput !== null) {
this.themeInput.select (defaultSettings.themeId);
this.callbacks.onThemeChange (defaultSettings.themeId);
}
});
}
};

View File

@ -14,15 +14,13 @@ OV.Website = class
this.hashHandler = new OV.HashHandler ();
this.cookieHandler = new OV.CookieHandler ();
this.toolbar = new OV.Toolbar (this.parameters.toolbarDiv);
this.sidebar = new OV.Sidebar (this.parameters.sidebarDiv);
this.navigator = new OV.Navigator (this.parameters.navigatorDiv, this.parameters.navigatorSplitterDiv);
this.sidebar = new OV.Sidebar (this.parameters.sidebarDiv);
this.eventHandler = new OV.EventHandler (this.parameters.eventHandler);
this.settings = new OV.Settings ();
this.modelLoader = new OV.ThreeModelLoader ();
this.themeHandler = new OV.ThemeHandler ();
this.highlightColor = new THREE.Color (0x8ec9f0);
this.detailsPanel = null;
this.settingsPanel = null;
this.model = null;
this.dialog = null;
}
@ -63,9 +61,7 @@ OV.Website = class
let safetyMargin = 0;
if (!OV.IsSmallWidth ()) {
navigatorWidth = this.navigator.GetWidth ();
if (this.sidebar.IsVisible ()) {
sidebarWidth = parseInt (this.parameters.sidebarDiv.outerWidth (true), 10);
}
sidebarWidth = this.sidebar.GetWidth ();
safetyMargin = 1;
}
@ -76,7 +72,7 @@ OV.Website = class
this.parameters.introDiv.outerHeight (contentHeight, true);
this.navigator.Resize (contentHeight);
this.sidebar.Resize ();
this.sidebar.Resize (contentHeight);
this.viewer.Resize (contentWidth, contentHeight);
}
@ -116,6 +112,7 @@ OV.Website = class
this.model = null;
this.viewer.Clear ();
this.navigator.Clear ();
this.sidebar.Clear ();
}
HidePopups ()
@ -124,7 +121,6 @@ OV.Website = class
this.dialog.Hide ();
this.dialog = null;
}
this.sidebar.HidePopups ();
}
OnModelFinished (importResult, threeObject)
@ -133,7 +129,7 @@ OV.Website = class
this.viewer.SetMainObject (threeObject);
this.viewer.SetUpVector (importResult.upVector, false);
this.navigator.FillTree (importResult);
this.settingsPanel.Update (this.model);
this.sidebar.Update (this.model);
this.FitModelToWindow (true);
}
@ -328,9 +324,6 @@ OV.Website = class
OV.ReplaceDefaultMaterialColor (this.model, this.settings.defaultColor);
this.modelLoader.ReplaceDefaultMaterialColor (this.settings.defaultColor);
}
if (this.settingsPanel !== null) {
this.settingsPanel.UpdateSettings (this.settings);
}
}
}
@ -515,85 +508,11 @@ OV.Website = class
InitSidebar ()
{
function AddSidebarButton (toolbar, eventHandler, sidebarPanel, onClick)
{
let button = toolbar.AddImageButton (sidebarPanel.image, sidebarPanel.title, () => {
eventHandler.HandleEvent ('sidebar_clicked', { item : sidebarPanel.image });
onClick ();
});
button.AddClass ('only_full_width only_on_model right');
return button;
}
function UpdateSidebarButtons (sidebar, sidebarPanels)
{
const visiblePanelId = sidebar.GetVisiblePanelId ();
for (let i = 0; i < sidebarPanels.length; i++) {
let sidebarPanel = sidebarPanels[i];
if (sidebarPanel.panelId === visiblePanelId) {
sidebarPanel.button.AddImageClass ('selected');
} else {
sidebarPanel.button.RemoveImageClass ('selected');
}
}
}
function ShowSidebar (sidebar, cookieHandler, sidebarPanels, panelId)
{
sidebar.Show (panelId);
UpdateSidebarButtons (sidebar, sidebarPanels);
cookieHandler.SetBoolVal ('ov_show_sidebar', sidebar.IsVisible ());
}
function ToggleSidebar (sidebar, cookieHandler, sidebarPanels, panelId)
{
if (sidebar.GetVisiblePanelId () !== panelId) {
ShowSidebar (sidebar, cookieHandler, sidebarPanels, panelId);
} else {
ShowSidebar (sidebar, cookieHandler, sidebarPanels, null);
}
}
this.detailsPanel = new OV.DetailsSidebarPanel (this.parameters.sidebarDiv);
this.settingsPanel = new OV.SettingsSidebarPanel (this.parameters.sidebarDiv);
let sidebarPanels = [
this.sidebar.Init (this.settings,
{
panelId : null,
panel : this.detailsPanel,
image : 'details',
title : 'Details panel',
button : null
},
{
panelId : null,
panel : this.settingsPanel,
image : 'settings',
title : 'Settings panel',
button : null
}
];
for (let id = 0; id < sidebarPanels.length; id++) {
let sidebarPanel = sidebarPanels[id];
sidebarPanel.panelId = this.sidebar.AddPanel (sidebarPanel.panel);
sidebarPanel.button = AddSidebarButton (this.toolbar, this.eventHandler, sidebarPanel, () => {
ToggleSidebar (this.sidebar, this.cookieHandler, sidebarPanels, sidebarPanel.panelId);
this.Resize ();
});
sidebarPanel.panel.Init ({
onClose : () => {
ShowSidebar (this.sidebar, this.cookieHandler, sidebarPanels, null);
onResize : () => {
this.Resize ();
}
});
}
let defaultSettings = new OV.Settings ();
this.settingsPanel.InitSettings (
this.settings,
defaultSettings,
{
},
onBackgroundColorChange : (newVal) => {
this.settings.backgroundColor = newVal;
this.settings.SaveToCookies (this.cookieHandler);
@ -613,9 +532,6 @@ OV.Website = class
}
}
);
let show = this.cookieHandler.GetBoolVal ('ov_show_sidebar', true);
ShowSidebar (this.sidebar, this.cookieHandler, sidebarPanels, show ? sidebarPanels[0].panelId : null);
}
InitNavigator ()
@ -699,14 +615,14 @@ OV.Website = class
return GetMaterialsForMesh (this.viewer, this.model, meshInstanceId);
},
onModelSelected : () => {
this.detailsPanel.AddObject3DProperties (this.model);
this.sidebar.AddObject3DProperties (this.model);
},
onMeshSelected : (meshInstanceId) => {
let meshInstance = this.model.GetMeshInstance (meshInstanceId);
this.detailsPanel.AddObject3DProperties (meshInstance);
this.sidebar.AddObject3DProperties (meshInstance);
},
onMaterialSelected : (materialIndex) => {
this.detailsPanel.AddMaterialProperties (this.model.GetMaterial (materialIndex));
this.sidebar.AddMaterialProperties (this.model.GetMaterial (materialIndex));
},
onResize : () => {
this.Resize ();