Use full file format names in export dialog.

This commit is contained in:
kovacsv 2021-12-25 10:21:23 +01:00
parent 6bb94d2ac7
commit b4f10e2ca1
5 changed files with 236 additions and 186 deletions

View File

@ -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)

View File

@ -55,13 +55,16 @@
<p>
<table>
<tr>
<th colspan="2">Format</th>
<th>Format</th>
<th>Extension</th>
<th>Type</th>
<th>Import</th>
<th>Export</th>
<th>Source</th>
<th>Comment</th>
</tr>
<tr>
<td>Wavefront</td>
<td>obj</td>
<td>text</td>
<td class="center green">&#x2713</td>
@ -70,6 +73,7 @@
<td></td>
</tr>
<tr>
<td>3D Studio</td>
<td>3ds</td>
<td>binary</td>
<td class="center green">&#x2713</td>
@ -78,6 +82,7 @@
<td></td>
</tr>
<tr>
<td rowspan="2">Stereolithography</td>
<td rowspan="2">stl</td>
<td>text</td>
<td class="center green">&#x2713</td>
@ -93,6 +98,7 @@
<td></td>
</tr>
<tr>
<td rowspan="2">Polygon File Format</td>
<td rowspan="2">ply</td>
<td>text</td>
<td class="center green">&#x2713</td>
@ -108,21 +114,24 @@
<td></td>
</tr>
<tr>
<td rowspan="2">gltf</td>
<td>text (.gltf)</td>
<td rowspan="2">glTF</td>
<td>gltf</td>
<td>text</td>
<td class="center green">&#x2713</td>
<td class="center green">&#x2713</td>
<td>Native</td>
<td></td>
</tr>
<tr>
<td>binary (.glb)</td>
<td>glb</td>
<td>binary</td>
<td class="center green">&#x2713</td>
<td class="center green">&#x2713</td>
<td>Native</td>
<td></td>
</tr>
<tr>
<td rowspan="2">Object File Format</td>
<td rowspan="2">off</td>
<td>text</td>
<td class="center green">&#x2713</td>
@ -138,6 +147,7 @@
<td></td>
</tr>
<tr>
<td>Rhinoceros 3D</td>
<td>3dm</td>
<td>binary</td>
<td class="center green">&#x2713</td>
@ -146,6 +156,7 @@
<td>experimental</td>
</tr>
<tr>
<td rowspan="2">Filmbox</td>
<td rowspan="2">fbx</td>
<td>text</td>
<td class="center green">&#x2713</td>
@ -161,6 +172,7 @@
<td>experimental</td>
</tr>
<tr>
<td>Collada</td>
<td>dae</td>
<td>text</td>
<td class="center green">&#x2713</td>
@ -169,6 +181,7 @@
<td>experimental</td>
</tr>
<tr>
<td>Virtual Reality Modeling Language</td>
<td>wrl</td>
<td>text</td>
<td class="center green">&#x2713</td>
@ -177,6 +190,7 @@
<td>experimental</td>
</tr>
<tr>
<td>3D Manufacturing Format</td>
<td>3mf</td>
<td>text</td>
<td class="center green">&#x2713</td>
@ -185,6 +199,7 @@
<td>experimental</td>
</tr>
<tr>
<td>Industry Foundation Classes</td>
<td>ifc</td>
<td>text</td>
<td class="center green">&#x2713</td>

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}
};