From b4f10e2ca1e175d4e992dbdc26c2ef6368e98cbb Mon Sep 17 00:00:00 2001 From: kovacsv Date: Sat, 25 Dec 2021 10:21:23 +0100 Subject: [PATCH] Use full file format names in export dialog. --- source/viewer/domutils.js | 15 ++ website/info/index.html | 23 ++- website/o3dv/css/controls.css | 8 + website/o3dv/css/dialogs.css | 31 +-- website/o3dv/js/exportdialog.js | 345 ++++++++++++++++---------------- 5 files changed, 236 insertions(+), 186 deletions(-) diff --git a/source/viewer/domutils.js b/source/viewer/domutils.js index f7a5522..6943c27 100644 --- a/source/viewer/domutils.js +++ b/source/viewer/domutils.js @@ -136,6 +136,21 @@ OV.AddRangeSlider = function (parentElement, min, max) return slider; }; +OV.AddSelect = function (parentElement, options, selectedIndex, onChange) +{ + let select = OV.AddDomElement (parentElement, 'select', 'ov_select'); + for (let option of options) { + OV.AddDomElement (select, 'option', null, option); + } + select.selectedIndex = selectedIndex; + if (onChange) { + select.addEventListener ('change', () => { + onChange (select.selectedIndex); + }); + } + return select; +}; + OV.AddToggle = function (parentElement, className) { function UpdateStatus (toggle, status) diff --git a/website/info/index.html b/website/info/index.html index aed3474..691b0ba 100644 --- a/website/info/index.html +++ b/website/info/index.html @@ -55,13 +55,16 @@

- + + + + @@ -70,6 +73,7 @@ + @@ -78,6 +82,7 @@ + @@ -93,6 +98,7 @@ + @@ -108,21 +114,24 @@ - - + + + - + + + @@ -138,6 +147,7 @@ + @@ -146,6 +156,7 @@ + @@ -161,6 +172,7 @@ + @@ -169,6 +181,7 @@ + @@ -177,6 +190,7 @@ + @@ -185,6 +199,7 @@ + diff --git a/website/o3dv/css/controls.css b/website/o3dv/css/controls.css index 162dd01..bb1b93b 100644 --- a/website/o3dv/css/controls.css +++ b/website/o3dv/css/controls.css @@ -128,6 +128,14 @@ input.ov_checkbox:checked border: 0px; } +select.ov_select +{ + color: var(--ov_dialog_foreground_color); + background: var(--ov_dialog_background_color); + padding: 3px; + border: 1px solid var(--ov_border_color); +} + input.ov_slider { height: 1px; diff --git a/website/o3dv/css/dialogs.css b/website/o3dv/css/dialogs.css index c6f4344..e38996e 100644 --- a/website/o3dv/css/dialogs.css +++ b/website/o3dv/css/dialogs.css @@ -96,19 +96,6 @@ div.ov_dialog div.ov_dialog_options height: 50px; } -div.ov_dialog div.ov_dialog_select -{ - margin: 20px 0px; - overflow: auto; -} - -div.ov_dialog div.ov_dialog_select div.ov_dialog_select_option -{ - width: 40px; - margin-right: 5px; - float: left; -} - div.ov_dialog div.ov_dialog_file_list { max-height: 105px; @@ -177,6 +164,24 @@ div.ov_dialog div.ov_dialog_row overflow: auto; } +div.ov_dialog div.ov_dialog_row_name +{ + width: 30%; + float: left; +} + +div.ov_dialog div.ov_dialog_row_value +{ + width: 70%; + float: left; +} + +div.ov_dialog select.ov_select +{ + width: 100%; + box-sizing: border-box; +} + div.ov_popup { color: var(--ov_dialog_foreground_color); diff --git a/website/o3dv/js/exportdialog.js b/website/o3dv/js/exportdialog.js index 659ae4f..e2ee3d7 100644 --- a/website/o3dv/js/exportdialog.js +++ b/website/o3dv/js/exportdialog.js @@ -1,190 +1,73 @@ OV.ExportType = { - Model : 1, - Image : 2 + Model : 0, + Image : 1 }; -OV.ExportDialog = class +OV.ExporterUI = class { - constructor (callbacks) + constructor (name) { - this.callbacks = callbacks; - this.model = null; - this.exportFormats = [ - { - name : 'obj', - formats : [ - { name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'obj' } - ] - }, - { - name : 'stl', - formats : [ - { name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'stl' }, - { name : 'binary', type: OV.ExportType.Model, format : OV.FileFormat.Binary, extension : 'stl' } - ] - }, - { - name : 'ply', - formats : [ - { name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'ply' }, - { name : 'binary', type: OV.ExportType.Model, format : OV.FileFormat.Binary, extension : 'ply' } - ] - }, - { - name : 'gltf', - formats : [ - { name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'gltf' }, - { name : 'binary', type: OV.ExportType.Model, format : OV.FileFormat.Binary, extension : 'glb' } - ] - }, - { - name : 'off', - formats : [ - { name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'off' } - ] - }, - { - name : '3dm', - formats : [ - { name : 'binary', type: OV.ExportType.Model, format : OV.FileFormat.Binary, extension : '3dm' } - ] - }, - { - name : 'png', - formats : [ - { name : 'current size', type: OV.ExportType.Image, width : null, height : null, extension : 'png' }, - { name : 'fixed size (1920x1080)', type: OV.ExportType.Image, width : 1920, height : 1080, extension : 'png' } - ] - } - ]; - this.formatParameters = { - exportFormatButtonDivs : [], - formatSettingsDiv : null, - selectedFormat : null - }; + this.name = name; } - Show (model, viewer) + GetType () { - if (model === null) { - let messageDialog = OV.ShowMessageDialog ( - 'Export Failed', - 'Please load a model before exporting.', - null - ); - this.callbacks.onDialog (messageDialog); - return; - } - - let mainDialog = new OV.ButtonDialog (); - let contentDiv = mainDialog.Init ('Export', [ - { - name : 'Close', - subClass : 'outline', - onClick () { - mainDialog.Hide (); - } - }, - { - name : 'Export', - onClick : () => { - let selectedFormat = this.formatParameters.selectedFormat; - if (selectedFormat === null) { - return; - } - mainDialog.Hide (); - this.ExportFormat (model, viewer); - } - } - ]); - - let text = 'Select a format from the below list to export your model. Please note that the export can take several second.'; - OV.AddDiv (contentDiv, 'ov_dialog_section', text); - - let exportFormatSelect = OV.AddDiv (contentDiv, 'ov_dialog_select'); - this.formatParameters.formatSettingsDiv = OV.AddDiv (contentDiv, 'ov_dialog_section ov_dialog_options'); - for (let i = 0; i < this.exportFormats.length; i++) { - let exportFormat = this.exportFormats[i]; - let exportFormatButton = OV.AddDiv (exportFormatSelect, 'ov_button outline ov_dialog_select_option', exportFormat.name); - this.formatParameters.exportFormatButtonDivs.push (exportFormatButton); - exportFormatButton.addEventListener ('click', () => { - this.OnExportFormatSelect (i); - }); - } - this.OnExportFormatSelect (0); - - mainDialog.Show (); - this.callbacks.onDialog (mainDialog); + return null; } - OnExportFormatSelect (exportFormatIndex) + GetName () { - OV.ClearDomElement (this.formatParameters.formatSettingsDiv); - for (let i = 0; i < this.formatParameters.exportFormatButtonDivs.length; i++) { - let exportFormatButtonDiv = this.formatParameters.exportFormatButtonDivs[i]; - if (i === exportFormatIndex) { - exportFormatButtonDiv.classList.remove ('outline'); - } else { - exportFormatButtonDiv.classList.add ('outline'); - } - } - - let exportFormat = this.exportFormats[exportFormatIndex]; - for (let i = 0; i < exportFormat.formats.length; i++) { - let format = exportFormat.formats[i]; - let formatDiv = OV.AddDiv (this.formatParameters.formatSettingsDiv, 'ov_dialog_row'); - let formatInput = OV.AddRadioButton (formatDiv, 'format', format.name, format.name, () => { - this.formatParameters.selectedFormat = format; - }); - if (i === 0) { - formatInput.checked = true; - this.formatParameters.selectedFormat = format; - } - } + return this.name; } - ExportFormat (model, viewer) + GenerateParametersUI (parametersDiv) { - let selectedFormat = this.formatParameters.selectedFormat; - if (selectedFormat === null) { - return; - } - if (selectedFormat.type === OV.ExportType.Model) { - let progressDialog = new OV.ProgressDialog (); - progressDialog.Init ('Exporting Model'); - progressDialog.Show (); - OV.RunTaskAsync (() => { - let exporter = new OV.Exporter (); - exporter.Export (model, selectedFormat.format, selectedFormat.extension, { - onError : () => { + } +}; + +OV.ModelExporterUI = class extends OV.ExporterUI +{ + constructor (name, format, extension) + { + super (name); + this.format = format; + this.extension = extension; + } + + GetType () + { + return OV.ExportType.Model; + } + + ExportModel (model, onDialog) + { + let progressDialog = new OV.ProgressDialog (); + progressDialog.Init ('Exporting Model'); + progressDialog.Show (); + + OV.RunTaskAsync (() => { + let exporter = new OV.Exporter (); + exporter.Export (model, this.format, this.extension, { + onError : () => { + progressDialog.Hide (); + }, + onSuccess : (files) => { + if (files.length === 0) { progressDialog.Hide (); - }, - onSuccess : (files) => { - if (files.length === 0) { - progressDialog.Hide (); - } else if (files.length === 1) { - progressDialog.Hide (); - let file = files[0]; - OV.DownloadArrayBufferAsFile (file.GetBufferContent (), file.GetName ()); - } else if (files.length > 1) { - progressDialog.Hide (); - this.ShowExportedFiles (files); - } + } else if (files.length === 1) { + progressDialog.Hide (); + let file = files[0]; + OV.DownloadArrayBufferAsFile (file.GetBufferContent (), file.GetName ()); + } else if (files.length > 1) { + progressDialog.Hide (); + let filesDialog = this.ShowExportedFiles (files); + onDialog (filesDialog); } - }); + } }); - } else if (selectedFormat.type === OV.ExportType.Image) { - let url = null; - if (selectedFormat.width === null || selectedFormat.height === null) { - let size = viewer.GetImageSize (); - url = viewer.GetImageAsDataUrl (size.width, size.height); - } else { - url = viewer.GetImageAsDataUrl (selectedFormat.width, selectedFormat.height); - } - OV.DownloadUrlAsFile (url, 'model.' + selectedFormat.extension); - } + }); } ShowExportedFiles (files) @@ -215,6 +98,130 @@ OV.ExportDialog = class } dialog.Show (); - this.callbacks.onDialog (dialog); + return dialog; + } +}; + +OV.ImageExporterUI = class extends OV.ExporterUI +{ + constructor (name, extension) + { + super (name); + this.extension = extension; + this.sizeSelect = null; + this.sizes = [ + { name : 'Current size', value : null }, + { name : '1280 x 720', value : [1280, 720] }, + { name : '1920 x 1080', value : [1920, 1080] } + ]; + } + + GetType () + { + return OV.ExportType.Image; + } + + GenerateParametersUI (parametersDiv) + { + function AddParameterSelect (parametersDiv, name, values, defaultIndex) + { + let parameterRow = OV.AddDiv (parametersDiv, 'ov_dialog_row'); + OV.AddDiv (parameterRow, 'ov_dialog_row_name', name); + let parameterValueDiv = OV.AddDiv (parameterRow, 'ov_dialog_row_value'); + return OV.AddSelect (parameterValueDiv, values, defaultIndex); + } + + let sizeNames = this.sizes.map (size => size.name); + this.sizeSelect = AddParameterSelect (parametersDiv, 'Image size', sizeNames, 1); + } + + ExportImage (viewer) + { + let selectedSize = this.sizes[this.sizeSelect.selectedIndex]; + let url = null; + if (selectedSize.value === null) { + let size = viewer.GetImageSize (); + url = viewer.GetImageAsDataUrl (size.width, size.height); + } else { + url = viewer.GetImageAsDataUrl (selectedSize.value[0], selectedSize.value[1]); + } + OV.DownloadUrlAsFile (url, 'model.' + this.extension); + } +}; + +OV.ExportDialog = class +{ + constructor (callbacks) + { + this.callbacks = callbacks; + this.selectedExporter = null; + this.parametersDiv = null; + + this.exporters = [ + new OV.ModelExporterUI ('Wavefront (.obj)', OV.FileFormat.Text, 'obj'), + new OV.ModelExporterUI ('Stereolithography Text (.stl)', OV.FileFormat.Text, 'stl'), + new OV.ModelExporterUI ('Stereolithography Binary (.stl)', OV.FileFormat.Binary, 'stl'), + new OV.ModelExporterUI ('Polygon File Format Text (.ply)', OV.FileFormat.Text, 'ply'), + new OV.ModelExporterUI ('Polygon File Format Binary (.ply)', OV.FileFormat.Binary, 'ply'), + new OV.ModelExporterUI ('glTF Text (.gltf)', OV.FileFormat.Text, 'gltf'), + new OV.ModelExporterUI ('glTF Binary (.glb)', OV.FileFormat.Binary, 'glb'), + new OV.ModelExporterUI ('Object File Format Text (.off)', OV.FileFormat.Text, 'off'), + new OV.ModelExporterUI ('Rhinoceros 3D (.3dm)', OV.FileFormat.Binary, '3dm'), + new OV.ImageExporterUI ('PNG Image (.png)', 'png') + ]; + } + + Show (model, viewer) + { + let mainDialog = new OV.ButtonDialog (); + let contentDiv = mainDialog.Init ('Export', [ + { + name : 'Close', + subClass : 'outline', + onClick () { + mainDialog.Hide (); + } + }, + { + name : 'Export', + onClick : () => { + mainDialog.Hide (); + this.ExportFormat (model, viewer); + } + } + ]); + + let text = 'Select the format from the list below, and adjust the settings of the selected format.'; + OV.AddDiv (contentDiv, 'ov_dialog_section', text); + + let formatRow = OV.AddDiv (contentDiv, 'ov_dialog_row'); + this.parametersDiv = OV.AddDiv (contentDiv); + let formatNames = this.exporters.map (exporter => exporter.GetName ()); + let defaultFormatIndex = 6; + OV.AddSelect (formatRow, formatNames, defaultFormatIndex, (selectedIndex) => { + this.OnFormatSelected (selectedIndex); + }); + this.OnFormatSelected (defaultFormatIndex); + + mainDialog.Show (); + this.callbacks.onDialog (mainDialog); + } + + OnFormatSelected (selectedIndex) + { + OV.ClearDomElement (this.parametersDiv); + this.selectedExporter = this.exporters[selectedIndex]; + this.selectedExporter.GenerateParametersUI (this.parametersDiv); + } + + ExportFormat (model, viewer) + { + if (this.selectedExporter.GetType () === OV.ExportType.Model) { + this.selectedExporter.ExportModel (model, (filesDialog) => { + this.callbacks.onDialog (filesDialog); + }); + } else if (this.selectedExporter.GetType () === OV.ExportType.Image) { + this.selectedExporter.ExportImage (viewer); + } } };
FormatFormatExtensionType Import Export Source Comment
Wavefront obj text
3D Studio 3ds binary
Stereolithography stl text
Polygon File Format ply text
gltftext (.gltf)glTFgltftext Native
binary (.glb)glbbinary Native
Object File Format off text
Rhinoceros 3D 3dm binary experimental
Filmbox fbx text experimental
Collada dae text experimental
Virtual Reality Modeling Language wrl text experimental
3D Manufacturing Format 3mf text experimental
Industry Foundation Classes ifc text