Redesign export dialog. Single files are downloaded immediately, multiple files are listed for download.

This commit is contained in:
Viktor Kovacs 2021-04-11 10:17:16 +02:00
parent 3607ab3649
commit 31b4935ac1
8 changed files with 236 additions and 92 deletions

View File

@ -54,6 +54,7 @@
"website/o3dv/treeview.js",
"website/o3dv/modal.js",
"website/o3dv/dialogs.js",
"website/o3dv/exportdialog.js",
"website/o3dv/modeldata.js",
"website/o3dv/info.js",
"website/o3dv/menu.js",

View File

@ -68,6 +68,7 @@
<script type="text/javascript" src="o3dv/treeview.js"></script>
<script type="text/javascript" src="o3dv/modal.js"></script>
<script type="text/javascript" src="o3dv/dialogs.js"></script>
<script type="text/javascript" src="o3dv/exportdialog.js"></script>
<script type="text/javascript" src="o3dv/modeldata.js"></script>
<script type="text/javascript" src="o3dv/info.js"></script>
<script type="text/javascript" src="o3dv/menu.js"></script>

View File

@ -68,6 +68,7 @@
<script type="text/javascript" src="o3dv/treeview.js"></script>
<script type="text/javascript" src="o3dv/modal.js"></script>
<script type="text/javascript" src="o3dv/dialogs.js"></script>
<script type="text/javascript" src="o3dv/exportdialog.js"></script>
<script type="text/javascript" src="o3dv/modeldata.js"></script>
<script type="text/javascript" src="o3dv/info.js"></script>
<script type="text/javascript" src="o3dv/menu.js"></script>

View File

@ -77,81 +77,6 @@ OV.ShowOpenUrlDialog = function (onOk)
return dialog;
};
OV.ShowExportDialog = function (model)
{
if (model === null) {
return OV.ShowMessageDialog ('Export Failed', 'Please load a model to export', null);
}
let dialog = new OV.ButtonDialog ();
let contentDiv = dialog.Init ('Export', [
{
name : 'Close',
onClick () {
dialog.Hide ();
}
}
]);
let text = 'Select a format from the below list to export your model. Please note that the export can take several second.';
$('<div>').html (text).addClass ('ov_dialog_section').appendTo (contentDiv);
let formats = [
{ name : 'obj (text)', format : OV.FileFormat.Text, extension : 'obj' },
{ name : 'stl (text)', format : OV.FileFormat.Text, extension : 'stl' },
{ name : 'stl (binary)', format : OV.FileFormat.Binary, extension : 'stl' },
{ name : 'ply (text)', format : OV.FileFormat.Text, extension : 'ply' },
{ name : 'ply (binary)', format : OV.FileFormat.Binary, extension : 'ply' },
{ name : 'gltf (text)', format : OV.FileFormat.Text, extension : 'gltf' },
{ name : 'gltf (binary)', format : OV.FileFormat.Binary, extension : 'glb' },
{ name : 'off (text)', format : OV.FileFormat.Text, extension : 'off' }
];
let formatSelect = $('<select>').addClass ('ov_dialog_select').appendTo (contentDiv);
$('<option>').html ('Select format').appendTo (formatSelect);
for (let i = 0; i < formats.length; i++) {
let format = formats[i];
$('<option>').html (format.name).appendTo (formatSelect);
}
let fileListSection = $('<div>').addClass ('ov_dialog_section').appendTo (contentDiv);
let fileList = $('<div>').addClass ('ov_dialog_file_list').addClass ('ov_thin_scrollbar').appendTo (fileListSection);
let createdUrls = [];
formatSelect.change (function () {
fileList.empty ();
let selectedIndex = formatSelect.prop ('selectedIndex');
if (selectedIndex < 1) {
return;
}
let selectedFormat = formats[selectedIndex - 1];
fileList.html ('Please wait...');
OV.RunTaskAsync (function () {
let exporter = new OV.Exporter ();
let files = exporter.Export (model, selectedFormat.format, selectedFormat.extension);
fileList.empty ();
for (let i = 0; i < files.length; i++) {
let file = files[i];
let url = OV.CreateObjectUrl (file.GetContent ());
let fileLink = $('<a>').addClass ('ov_dialog_file_link').appendTo (fileList);
fileLink.attr ('href', url);
fileLink.attr ('download', file.GetName ());
$('<img>').addClass ('ov_dialog_file_link_icon').attr ('src', 'assets/images/dialog/file_download.svg').appendTo (fileLink);
$('<div>').addClass ('ov_dialog_file_link_text').html (file.GetName ()).appendTo (fileLink);
}
});
});
dialog.SetCloseHandler (function () {
for (let i = 0; i < createdUrls.length; i++) {
OV.RevokeObjectUrl (createdUrls[i]);
}
});
dialog.Show ();
return dialog;
};
OV.ShowEmbeddingDialog = function (importer, importSettings, camera)
{
function AddCheckboxLine (parentDiv, text, onChange)

View File

@ -0,0 +1,191 @@
OV.ExportDialog = class
{
constructor (callbacks)
{
this.callbacks = callbacks;
this.model = null;
this.exportFormats = [
{
name : 'obj',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'obj' }
]
},
{
name : 'stl',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'stl' },
{ name : 'binary', format : OV.FileFormat.Binary, extension : 'stl' }
]
},
{
name : 'ply',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'ply' },
{ name : 'binary', format : OV.FileFormat.Binary, extension : 'ply' }
]
},
{
name : 'gltf',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'gltf' },
{ name : 'binary', format : OV.FileFormat.Binary, extension : 'glb' }
]
},
{
name : 'off',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'off' }
]
}
];
this.formatParameters = {
exportFormatButtonDivs : [],
formatSettingsDiv : null,
selectedFormat : null
};
}
Show (model)
{
if (model === null) {
let messageDialog = OV.ShowMessageDialog (
'Export Failed',
'Please load a model before exporting.',
null
);
this.callbacks.onDialog (messageDialog);
return;
}
let obj = this;
let mainDialog = new OV.ButtonDialog ();
let contentDiv = mainDialog.Init ('Export', [
{
name : 'Close',
subClass : 'outline',
onClick () {
mainDialog.Hide ();
}
},
{
name : 'Export',
onClick () {
let selectedFormat = obj.formatParameters.selectedFormat;
if (selectedFormat === null) {
return;
}
mainDialog.Hide ();
obj.ExportFormat (model);
}
}
]);
let text = 'Select a format from the below list to export your model. Please note that the export can take several second.';
$('<div>').html (text).addClass ('ov_dialog_section').appendTo (contentDiv);
let buttonWidth = 40;
let optionsHeight = 50;
let exportFormatSelect = $('<div>').addClass ('ov_dialog_select').appendTo (contentDiv);
this.formatParameters.formatSettingsDiv = $('<div>').addClass ('ov_dialog_section').height (optionsHeight).appendTo (contentDiv);
for (let i = 0; i < this.exportFormats.length; i++) {
let exportFormat = this.exportFormats[i];
let exportFormatButton = $('<div>').addClass ('ov_dialog_select_option').html (exportFormat.name).width (buttonWidth).appendTo (exportFormatSelect);
this.formatParameters.exportFormatButtonDivs.push (exportFormatButton);
exportFormatButton.click (function () {
obj.OnExportFormatSelect (i);
});
}
this.OnExportFormatSelect (0);
mainDialog.Show ();
this.callbacks.onDialog (mainDialog);
}
OnExportFormatSelect (exportFormatIndex)
{
this.formatParameters.formatSettingsDiv.empty ();
for (let i = 0; i < this.formatParameters.exportFormatButtonDivs.length; i++) {
let exportFormatButtonDiv = this.formatParameters.exportFormatButtonDivs[i];
if (i === exportFormatIndex) {
exportFormatButtonDiv.addClass ('selected');
} else {
exportFormatButtonDiv.removeClass ('selected');
}
}
let obj = this;
let exportFormat = this.exportFormats[exportFormatIndex];
for (let i = 0; i < exportFormat.formats.length; i++) {
let format = exportFormat.formats[i];
let formatDiv = $('<div>').addClass ('ov_dialog_table_row').appendTo (this.formatParameters.formatSettingsDiv);
let formatInput = $('<input>').addClass ('ov_dialog_table_radio').attr ('type', 'radio').attr ('id', format.name).attr ('name', 'format').appendTo (formatDiv);
$('<label>').attr ('for', format.name).html (format.name).appendTo (formatDiv);
if (i === 0) {
formatInput.prop ('checked', true);
this.formatParameters.selectedFormat = format;
}
formatInput.change (function () {
obj.formatParameters.selectedFormat = format;
});
}
}
ExportFormat (model)
{
let format = this.formatParameters.selectedFormat;
if (format === null) {
return;
}
let obj = this;
let progressDialog = new OV.ProgressDialog ();
progressDialog.Show ('Exporting Model');
OV.RunTaskAsync (function () {
let exporter = new OV.Exporter ();
let files = exporter.Export (model, format.format, format.extension);
if (files.length === 0) {
progressDialog.Hide ();
} else if (files.length === 1) {
progressDialog.Hide ();
let file = files[0];
OV.DownloadArrayBufferAsFile (file.GetContent (), file.GetName ());
} else if (files.length > 1) {
progressDialog.Hide ();
obj.ShowExportedFiles (files);
}
});
}
ShowExportedFiles (files)
{
let dialog = new OV.ButtonDialog ();
let contentDiv = dialog.Init ('Exported Files', [
{
name : 'Close',
onClick () {
dialog.Hide ();
}
}
]);
let text = 'You can download your exported files here.';
$('<div>').html (text).addClass ('ov_dialog_section').appendTo (contentDiv);
let fileListSection = $('<div>').addClass ('ov_dialog_section').appendTo (contentDiv);
let fileList = $('<div>').addClass ('ov_dialog_file_list').addClass ('ov_thin_scrollbar').appendTo (fileListSection);
for (let i = 0; i < files.length; i++) {
let file = files[i];
let url = OV.CreateObjectUrl (file.GetContent ());
let fileLink = $('<a>').addClass ('ov_dialog_file_link').appendTo (fileList);
fileLink.attr ('href', url);
fileLink.attr ('download', file.GetName ());
$('<img>').addClass ('ov_dialog_file_link_icon').attr ('src', 'assets/images/dialog/file_download.svg').appendTo (fileLink);
$('<div>').addClass ('ov_dialog_file_link_text').html (file.GetName ()).appendTo (fileLink);
}
dialog.Show ();
this.callbacks.onDialog (dialog);
}
};

View File

@ -100,6 +100,16 @@ OV.CopyToClipboard = function (text)
document.body.removeChild (input);
};
OV.DownloadArrayBufferAsFile = function (arrayBuffer, fileName)
{
let link = document.createElement ('a');
link.href = OV.CreateObjectUrl (arrayBuffer);
link.download = fileName;
document.body.appendChild (link);
link.click ();
document.body.removeChild (link);
};
OV.CreateIconButton = function (iconName, hoverIconName, title, link)
{
let buttonLink = $('<a>');

View File

@ -449,23 +449,28 @@ div.ov_dialog textarea.ov_dialog_textarea
box-sizing: border-box;
}
div.ov_dialog select.ov_dialog_select
div.ov_dialog div.ov_dialog_select
{
background-image: url('../assets/images/dialog/arrow_down.svg');
background-repeat: no-repeat;
background-size: 18px 18px;
background-position: right 10px center;
font-size: 14px;
margin: 10px 0px;
width: 100%;
padding: 10px;
border: 1px solid #cccccc;
margin: 20px 0px;
overflow: auto;
}
div.ov_dialog div.ov_dialog_select_option
{
color: #3393bd;
text-align: center;
padding: 3px;
margin-right: 5px;
border: 1px solid #3393bd;
border-radius: 5px;
outline: none;
box-sizing: border-box;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
float: left;
}
div.ov_dialog div.ov_dialog_select_option.selected
{
color: #ffffff;
background: #3393bd;
}
div.ov_dialog input.ov_dialog_color
@ -531,6 +536,11 @@ div.ov_dialog div.ov_dialog_table_row_value
float: left;
}
div.ov_dialog input.ov_dialog_table_radio
{
margin-right: 10px;
}
div.ov_popup
{
background: #ffffff;

View File

@ -280,8 +280,13 @@ OV.Website = class
});
AddSeparator (this.toolbar, true);
AddButton (this.toolbar, 'export', 'Export model', true, function () {
obj.dialog = OV.ShowExportDialog (obj.model);
});
let exportDialog = new OV.ExportDialog ({
onDialog : function (dialog) {
obj.dialog = dialog;
}
});
exportDialog.Show (obj.model);
});
AddButton (this.toolbar, 'embed', 'Get embedding code', true, function () {
obj.dialog = OV.ShowEmbeddingDialog (importer, obj.importSettings, obj.viewer.GetCamera ());
});