Make mesh visibility options available from context menu #102

This commit is contained in:
kovacsv 2021-07-24 13:49:22 +02:00
parent d911e45988
commit 9405aff3dd
9 changed files with 214 additions and 88 deletions

View File

@ -245,6 +245,7 @@ OV.Navigation = class
this.onUpdate = null;
this.onClick = null;
this.onContext = null;
if (this.canvas.addEventListener) {
this.canvas.addEventListener ('mousedown', this.OnMouseDown.bind (this));
@ -271,6 +272,11 @@ OV.Navigation = class
this.onClick = onClick;
}
SetContextMenuHandler (onContext)
{
this.onContext = onContext;
}
IsFixUpVector ()
{
return this.fixUpVector;
@ -375,12 +381,15 @@ OV.Navigation = class
OnMouseDown (ev)
{
ev.preventDefault ();
this.mouse.Down (this.canvas, ev);
this.clickDetector.Down (ev);
}
OnMouseMove (ev)
{
ev.preventDefault ();
this.mouse.Move (this.canvas, ev);
this.clickDetector.Move ();
if (!this.mouse.IsButtonDown ()) {
@ -403,6 +412,8 @@ OV.Navigation = class
OnMouseUp (ev)
{
ev.preventDefault ();
this.mouse.Up (this.canvas, ev);
this.clickDetector.Up (ev);
if (this.clickDetector.IsClick ()) {
@ -413,6 +424,8 @@ OV.Navigation = class
OnMouseLeave (ev)
{
ev.preventDefault ();
this.mouse.Leave (this.canvas, ev);
this.clickDetector.Leave (ev);
}
@ -420,12 +433,14 @@ OV.Navigation = class
OnTouchStart (ev)
{
ev.preventDefault ();
this.touch.Start (this.canvas, ev);
}
OnTouchMove (ev)
{
ev.preventDefault ();
this.touch.Move (this.canvas, ev);
if (!this.touch.IsFingerDown ()) {
return;
@ -450,12 +465,14 @@ OV.Navigation = class
OnTouchEnd (ev)
{
ev.preventDefault ();
this.touch.End (this.canvas, ev);
}
OnMouseWheel (ev)
{
ev.preventDefault ();
let params = ev || window.event;
let delta = -params.deltaY / 40;
@ -471,6 +488,11 @@ OV.Navigation = class
OnContextMenu (ev)
{
ev.preventDefault ();
this.clickDetector.Up (ev);
if (this.clickDetector.IsClick ()) {
this.Context (ev.clientX, ev.clientY);
}
}
Orbit (angleX, angleY)
@ -541,5 +563,17 @@ OV.Navigation = class
let mouseCoords = OV.GetClientCoordinates (this.canvas, clientX, clientY);
this.onClick (button, isCtrlPressed, mouseCoords);
}
}
}
Context (clientX, clientY)
{
if (this.onContext) {
let globalCoords = {
x : clientX,
y : clientY
};
let localCoords = OV.GetClientCoordinates (this.canvas, clientX, clientY);
this.onContext (globalCoords, localCoords);
}
}
};

View File

@ -180,6 +180,11 @@ OV.Viewer = class
this.navigation.SetClickHandler (onClick);
}
SetContextMenuHandler (onContext)
{
this.navigation.SetContextMenuHandler (onContext);
}
SetBackgroundColor (color)
{
let hexColor = '#' + OV.ColorToHexString (color);

View File

@ -17,10 +17,16 @@ OV.ShowMessageDialog = function (title, message, subMessage)
return dialog;
};
OV.ShowListPopup = function (button, items, callbacks)
OV.ShowListPopup = function (items, callbacks)
{
if (items.length === 0) {
return null;
}
let popup = new OV.ListPopup ();
popup.Init (button);
popup.Init (() => {
return callbacks.calculatePosition (popup.GetContentDiv ());
});
for (let i = 0; i < items.length; i++) {
let item = items[i];
popup.AddListItem (item, {

View File

@ -157,7 +157,8 @@ OV.ExportDialog = class
if (selectedFormat.type === OV.ExportType.Model) {
let progressDialog = new OV.ProgressDialog ();
progressDialog.Show ('Exporting Model');
progressDialog.Init ('Exporting Model');
progressDialog.Show ();
OV.RunTaskAsync (() => {
let exporter = new OV.Exporter ();
exporter.AddExporter (new OV.Exporter3dm ());

View File

@ -1,4 +1,5 @@
OV.FeatureSet =
{
SettingsPanel : false
SettingsPanel : false,
ContextMenu : false
};

View File

@ -38,7 +38,8 @@ OV.InitModelLoader = function (modelLoader, callbacks)
CloseDialogIfOpen (errorDialog);
callbacks.onStart ();
progressDialog = new OV.ProgressDialog ();
progressDialog.Show ('Loading Model');
progressDialog.Init ('Loading Model');
progressDialog.Show ();
},
onImportStart : () => {
progressDialog.SetText ('Importing Model');

View File

@ -5,7 +5,7 @@ OV.Modal = class
this.modalDiv = $('<div>').css ('position', 'absolute');
this.overlayDiv = null;
this.resizeHandler = null;
this.customResizeHandler = null;
this.positionCalculator = null;
this.closeHandler = null;
this.isOpen = false;
this.closeable = true;
@ -21,9 +21,9 @@ OV.Modal = class
this.closeable = closeable;
}
SetCustomResizeHandler (customResizeHandler)
SetPositionCalculator (positionCalculator)
{
this.customResizeHandler = customResizeHandler;
this.positionCalculator = positionCalculator;
}
SetCloseHandler (closeHandler)
@ -43,6 +43,11 @@ OV.Modal = class
windowObj.bind ('resize', this.resizeHandler);
if (this.closeable) {
this.overlayDiv.click ((ev) => {
ev.preventDefault ();
this.Close ();
});
this.overlayDiv.contextmenu ((ev) => {
ev.preventDefault ();
this.Close ();
});
}
@ -86,33 +91,69 @@ OV.Modal = class
left : 0,
top : 0
});
if (this.customResizeHandler) {
this.customResizeHandler (this.modalDiv);
} else {
this.modalDiv.offset ({
left : (windowWidth - this.modalDiv.outerWidth ()) / 2,
top : (windowHeight - this.modalDiv.outerHeight ()) / 3
});
let positionX = (windowWidth - this.modalDiv.outerWidth ()) / 2;
let positionY = (windowHeight - this.modalDiv.outerHeight ()) / 3;
if (this.positionCalculator !== null) {
let calculatedPosition = this.positionCalculator ();
positionX = calculatedPosition.x;
positionY = calculatedPosition.y;
}
this.modalDiv.offset ({
left : positionX,
top : positionY
});
}
};
OV.ProgressDialog = class
OV.Dialog = class
{
constructor ()
{
this.modal = new OV.Modal ();
}
GetContentDiv ()
{
return this.modal.GetContentDiv ();
}
SetCloseable (closeable)
{
this.modal.SetCloseable (closeable);
}
SetCloseHandler (closeHandler)
{
this.modal.SetCloseHandler (closeHandler);
}
SetPositionCalculator (positionCalculator)
{
this.modal.SetPositionCalculator (positionCalculator);
}
Show ()
{
this.modal.Open ();
}
Hide ()
{
this.modal.Close ();
}
};
OV.ProgressDialog = class extends OV.Dialog
{
constructor ()
{
super ();
this.modal.SetCloseable (false);
this.imageDiv = null;
this.textDiv = null;
}
SetText (text)
{
this.textDiv.html (text);
}
Show (text)
Init (text)
{
let contentDiv = this.modal.GetContentDiv ();
contentDiv.addClass ('ov_progress');
@ -121,20 +162,19 @@ OV.ProgressDialog = class
this.textDiv = $('<div>').addClass ('ov_progress_text').appendTo (contentDiv);
this.SetText (text);
this.modal.Open ();
}
Hide ()
SetText (text)
{
this.modal.Close ();
this.textDiv.html (text);
}
};
OV.ButtonDialog = class
OV.ButtonDialog = class extends OV.Dialog
{
constructor ()
{
this.modal = new OV.Modal ();
super ();
}
Init (title, buttons)
@ -163,65 +203,22 @@ OV.ButtonDialog = class
return dialogContentDiv;
}
SetCloseable (closeable)
{
this.modal.SetCloseable (closeable);
}
SetCloseHandler (closeHandler)
{
this.modal.SetCloseHandler (closeHandler);
}
Show ()
{
this.modal.Open ();
}
Hide ()
{
this.modal.Close ();
}
};
OV.PopupDialog = class
OV.PopupDialog = class extends OV.Dialog
{
constructor ()
{
this.modal = new OV.Modal ();
super ();
}
Init (parentItem)
Init (positionCalculator)
{
let contentDiv = this.modal.GetContentDiv ();
contentDiv.addClass ('ov_popup');
this.modal.SetCustomResizeHandler ((modalDiv) => {
let offset = parentItem.offset ();
let left = offset.left + parentItem.outerWidth (false);
let bottom = offset.top + parentItem.outerHeight (false);
modalDiv.offset ({
left : left,
top : bottom - modalDiv.outerHeight (true)
});
});
this.modal.SetPositionCalculator (positionCalculator);
return contentDiv;
}
SetCustomResizeHandler (customResizeHandler)
{
this.modal.SetCustomResizeHandler (customResizeHandler);
}
Show ()
{
this.modal.Open ();
}
Hide ()
{
this.modal.Close ();
}
};
OV.ListPopup = class extends OV.PopupDialog
@ -232,9 +229,9 @@ OV.ListPopup = class extends OV.PopupDialog
this.listDiv = null;
}
Init (parentItem)
Init (positionCalculator)
{
let contentDiv = super.Init (parentItem);
let contentDiv = super.Init (positionCalculator);
this.listDiv = $('<div>').addClass ('ov_popup_list').addClass ('ov_thin_scrollbar').appendTo (contentDiv);
return contentDiv;
}

View File

@ -41,15 +41,22 @@ OV.NavigatorInfoPanel = class
if (meshItems.length === 0) {
return;
}
this.popup = OV.ShowListPopup (button, meshItems, {
onHoverStart : function (index) {
this.popup = OV.ShowListPopup (meshItems, {
calculatePosition : (contentDiv) => {
let offset = button.offset ();
return {
x : offset.left + button.outerWidth (false),
y : offset.top + button.outerHeight (false) - contentDiv.outerHeight (true)
};
},
onHoverStart : (index) => {
const meshItem = usedByMeshes[index];
callbacks.onMeshHover (meshItem.index);
},
onHoverStop : function (index) {
onHoverStop : (index) => {
callbacks.onMeshHover (null);
},
onClick : function (index) {
onClick : (index) => {
const meshItem = usedByMeshes[index];
callbacks.onMeshSelect (meshItem.index);
}
@ -75,13 +82,20 @@ OV.NavigatorInfoPanel = class
let materialsText = 'Materials (' + materialItems.length + ')';
this.CreateButton (this.parentDiv, materialsText, (button) => {
this.popup = OV.ShowListPopup (button, materialItems, {
this.popup = OV.ShowListPopup (materialItems, {
calculatePosition : (contentDiv) => {
let offset = button.offset ();
return {
x : offset.left + button.outerWidth (false),
y : offset.top + button.outerHeight (false) - contentDiv.outerHeight (true)
};
},
onClick : (index) => {
let usedMaterial = usedMaterials[index];
callbacks.onMaterialSelect (usedMaterial.index);
}
});
});
});
}
CreateButton (parentDiv, buttonText, onClick)
@ -214,16 +228,20 @@ OV.Navigator = class
return meshData.IsVisible ();
}
IsolateMesh (meshIndex)
IsMeshIsolated (meshIndex)
{
let isIsolated = true;
for (let i = 0; i < this.modelData.MeshCount (); i++) {
let meshData = this.modelData.GetMeshData (i);
if (i !== meshIndex && meshData.IsVisible ()) {
isIsolated = false;
break;
return false;
}
}
return true;
}
IsolateMesh (meshIndex)
{
let isIsolated = this.IsMeshIsolated (meshIndex);
for (let i = 0; i < this.modelData.MeshCount (); i++) {
let meshData = this.modelData.GetMeshData (i);
if (i === meshIndex || isIsolated) {
@ -248,7 +266,7 @@ OV.Navigator = class
return this.tempSelectedMeshIndex;
}
if (this.selection === null || this.selection.type !== OV.SelectionType.Mesh) {
return -1;
return null;
}
return this.selection.index;
}

View File

@ -54,6 +54,7 @@ OV.Website = class
this.InitCookieConsent ();
this.viewer.SetClickHandler (this.OnModelClicked.bind (this));
this.viewer.SetContextMenuHandler (this.OnModelContextMenu.bind (this));
this.Resize ();
this.hashHandler.SetEventListener (this.OnHashChange.bind (this));
@ -141,6 +142,68 @@ OV.Website = class
}
}
OnModelContextMenu (globalMouseCoordinates, mouseCoordinates)
{
if (!OV.FeatureSet.ContextMenu) {
return;
}
let meshUserData = this.viewer.GetMeshUserDataUnderMouse (mouseCoordinates);
let items = [];
if (meshUserData === null) {
items = [
{
name : 'Fit model to window',
onClick : () => {
this.FitModelToWindow (false);
}
}
];
} else {
let meshIndex = meshUserData.originalMeshIndex;
let isSelectedMesh = (meshIndex === this.navigator.GetSelectedMeshIndex ());
let isMeshIsolated = this.navigator.IsMeshIsolated (meshIndex);
items = [
{
name : isSelectedMesh ? 'Deselect mesh' : 'Select mesh',
onClick : () => {
this.navigator.SetSelection (new OV.Selection (OV.SelectionType.Mesh, meshIndex));
}
},
{
name : 'Hide mesh',
onClick : () => {
this.navigator.ToggleMeshVisibility (meshIndex);
}
},
{
name : 'Fit to window',
onClick : () => {
this.navigator.FitMeshToWindow (meshIndex);
}
},
{
name : isMeshIsolated ? 'Remove mesh isolation' : 'Isolate mesh',
onClick : () => {
this.navigator.IsolateMesh (meshIndex);
}
}
];
}
this.dialog = OV.ShowListPopup (items, {
calculatePosition : (contentDiv) => {
return {
x : globalMouseCoordinates.x,
y : globalMouseCoordinates.y
};
},
onClick : (index) => {
let clickedItem = items[index];
clickedItem.onClick ();
}
});
}
OpenFileBrowserDialog ()
{
this.parameters.fileInput.trigger ('click');