ImporterApp = function ()
{
this.viewer = null;
this.fileNames = null;
this.inGenerate = false;
this.dialog = null;
};
ImporterApp.prototype.Init = function ()
{
if (!JSM.IsWebGLEnabled () || !JSM.IsFileApiEnabled ()) {
while (document.body.lastChild) {
document.body.removeChild (document.body.lastChild);
}
var div = document.createElement ('div');
div.className = 'nosupport';
div.innerHTML = [
'
',
this.GetWelcomeText (),
'
You need a browser which supports the following technologies: WebGL, WebGLRenderingContext, File, FileReader, FileList, Blob, URL.
',
'
'
].join ('');
document.body.appendChild (div);
return;
}
var myThis = this;
var top = document.getElementById ('top');
var importerButtons = new ImporterButtons (top);
importerButtons.AddLogo ('Online 3D Viewer v 0.2', function () { myThis.WelcomeDialog (); });
importerButtons.AddButton ('images/openfile.png', 'Open File', function () { myThis.OpenFile (); });
importerButtons.AddButton ('images/fitinwindow.png', 'Fit In Window', function () { myThis.FitInWindow (); });
importerButtons.AddButton ('images/fixup.png', 'Enable/Disable Fixed Up Vector', function () { myThis.SetFixUp (); });
importerButtons.AddButton ('images/top.png', 'Set Up Vector (Z)', function () { myThis.SetNamedView ('z'); });
importerButtons.AddButton ('images/bottom.png', 'Set Up Vector (-Z)', function () { myThis.SetNamedView ('-z'); });
importerButtons.AddButton ('images/front.png', 'Set Up Vector (Y)', function () { myThis.SetNamedView ('y'); });
importerButtons.AddButton ('images/back.png', 'Set Up Vector (-Y)', function () { myThis.SetNamedView ('-y'); });
importerButtons.AddButton ('images/left.png', 'Set Up Vector (X)', function () { myThis.SetNamedView ('x'); });
importerButtons.AddButton ('images/right.png', 'Set Up Vector (-X)', function () { myThis.SetNamedView ('-x'); });
this.dialog = new FloatingDialog ();
window.addEventListener ('resize', this.Resize.bind (this), false);
this.Resize ();
this.viewer = new ImporterViewer ();
this.viewer.Init ('example');
window.addEventListener ('dragover', this.DragOver.bind (this), false);
window.addEventListener ('drop', this.Drop.bind (this), false);
var fileInput = document.getElementById ('file');
fileInput.addEventListener ('change', this.FileSelected.bind (this), false);
this.WelcomeDialog ();
};
ImporterApp.prototype.WelcomeDialog = function ()
{
var dialogText = [
'',
this.GetWelcomeText (),
'
',
].join ('');
this.dialog.Open ({
title : 'Welcome',
text : dialogText,
buttons : [
{
text : 'ok',
callback : function (dialog) {
dialog.Close ();
}
}
]
});
};
ImporterApp.prototype.GetWelcomeText = function ()
{
var welcomeText = [
'Welcome to Online 3D Viewer!
',
'Here you can view your local 3D models online. Just simply drag and drop 3D files and textures to this browser window or use the open button above.
',
'Supported formats: 3ds, obj, stl.
',
'Powered by
Three.js and
JSModeler.
',
'',
].join ('');
return welcomeText;
};
ImporterApp.prototype.Resize = function ()
{
function SetWidth (elem, value)
{
elem.width = value;
elem.style.width = value + 'px';
}
function SetHeight (elem, value)
{
elem.height = value;
elem.style.height = value + 'px';
}
var top = document.getElementById ('top');
var left = document.getElementById ('left');
var canvas = document.getElementById ('example');
var height = document.body.clientHeight - top.offsetHeight;
SetHeight (canvas, 0);
SetWidth (canvas, 0);
SetHeight (left, height);
SetHeight (canvas, height);
SetWidth (canvas, document.body.clientWidth - left.offsetWidth);
this.dialog.Resize ();
};
ImporterApp.prototype.JsonLoaded = function (progressBar)
{
var jsonData = this.viewer.GetJsonData ();
this.meshVisibility = {};
var i;
for (i = 0; i < jsonData.meshes.length; i++) {
this.meshVisibility[i] = true;
}
this.Generate (progressBar);
};
ImporterApp.prototype.GenerateMenu = function ()
{
function AddDefaultGroup (menu, name)
{
var group = menu.AddGroup (name, {
openCloseButton : {
visible : false,
open : 'images/opened.png',
close : 'images/closed.png',
title : 'Show/Hide ' + name
}
});
return group;
}
function AddInformation (infoGroup, jsonData)
{
var infoTable = new InfoTable (infoGroup);
var materialCount = jsonData.materials.length;
var vertexCount = 0;
var triangleCount = 0;
var i, j, mesh, triangles;
for (i = 0; i < jsonData.meshes.length; i++) {
mesh = jsonData.meshes[i];
vertexCount += mesh.vertices.length / 3;
for (j = 0; j < mesh.triangles.length; j++) {
triangles = mesh.triangles[j];
triangleCount += triangles.parameters.length / 9;
}
}
infoTable.AddRow ('Material count', materialCount);
infoTable.AddRow ('Vertex count', vertexCount);
infoTable.AddRow ('Triangle count', triangleCount);
}
function AddMaterial (importerMenu, material)
{
importerMenu.AddSubItem (materialsGroup, material.name, {
openCloseButton : {
visible : false,
open : 'images/info.png',
close : 'images/info.png',
onOpen : function (content, material) {
var table = new InfoTable (content);
table.AddColorRow ('Ambient', material.ambient);
table.AddColorRow ('Diffuse', material.diffuse);
table.AddColorRow ('Specular', material.specular);
table.AddRow ('Shininess', material.shininess.toFixed (2));
table.AddRow ('Opacity', material.opacity.toFixed (2));
},
title : 'Show/Hide Information',
userData : material
}
});
}
function AddMesh (importerApp, importerMenu, mesh, meshIndex)
{
importerMenu.AddSubItem (meshesGroup, mesh.name, {
openCloseButton : {
visible : false,
open : 'images/info.png',
close : 'images/info.png',
onOpen : function (content, mesh) {
var table = new InfoTable (content);
var min = new JSM.Coord (JSM.Inf, JSM.Inf, JSM.Inf);
var max = new JSM.Coord (-JSM.Inf, -JSM.Inf, -JSM.Inf);
var i, vertex;
for (i = 0; i < mesh.vertices.length; i = i + 3) {
vertex = new JSM.Coord (mesh.vertices[i], mesh.vertices[i + 1], mesh.vertices[i + 2]);
min.x = JSM.Minimum (min.x, vertex.x);
min.y = JSM.Minimum (min.y, vertex.y);
min.z = JSM.Minimum (min.z, vertex.z);
max.x = JSM.Maximum (max.x, vertex.x);
max.y = JSM.Maximum (max.y, vertex.y);
max.z = JSM.Maximum (max.z, vertex.z);
}
table.AddRow ('X Size', (max.x - min.x).toFixed (2));
table.AddRow ('Y Size', (max.y - min.y).toFixed (2));
table.AddRow ('Z Size', (max.z - min.z).toFixed (2));
var triangleCount = 0;
var triangles;
for (i = 0; i < mesh.triangles.length; i++) {
triangles = mesh.triangles[i];
triangleCount += triangles.parameters.length / 9;
}
table.AddRow ('Vertex count', mesh.vertices.length / 3);
table.AddRow ('Triangle count', triangleCount);
},
title : 'Show/Hide Information',
userData : mesh
},
userButton : {
visible : true,
onCreate : function (image) {
image.src = 'images/visible.png';
},
onClick : function (image, meshIndex) {
var visible = importerApp.ShowHideMesh (meshIndex);
image.src = visible ? 'images/visible.png' : 'images/hidden.png';
},
title : 'Show/Hide Mesh',
userData : meshIndex
}
});
}
var jsonData = this.viewer.GetJsonData ();
var menu = document.getElementById ('menu');
var importerMenu = new ImporterMenu (menu);
var filesGroup = AddDefaultGroup (importerMenu, 'Files');
importerMenu.AddSubItem (filesGroup, this.fileNames.main);
var i;
for (i = 0; i < this.fileNames.requested.length; i++) {
importerMenu.AddSubItem (filesGroup, this.fileNames.requested[i]);
}
if (this.fileNames.missing.length > 0) {
var missingFilesGroup = AddDefaultGroup (importerMenu, 'Missing Files');
for (i = 0; i < this.fileNames.missing.length; i++) {
importerMenu.AddSubItem (missingFilesGroup, this.fileNames.missing[i]);
}
}
var infoGroup = AddDefaultGroup (importerMenu, 'Information');
AddInformation (infoGroup, jsonData);
var materialsGroup = AddDefaultGroup (importerMenu, 'Materials');
var material;
for (i = 0; i < jsonData.materials.length; i++) {
material = jsonData.materials[i];
AddMaterial (importerMenu, material);
}
var meshesGroup = AddDefaultGroup (importerMenu, 'Meshes');
var mesh;
for (i = 0; i < jsonData.meshes.length; i++) {
mesh = jsonData.meshes[i];
AddMesh (this, importerMenu, mesh, i);
}
};
ImporterApp.prototype.GenerateError = function (errorMessage)
{
this.viewer.RemoveMeshes ();
var menu = document.getElementById ('menu');
while (menu.lastChild) {
menu.removeChild (menu.lastChild);
}
this.dialog.Open ({
title : 'Error',
text : '' + errorMessage + '
',
buttons : [
{
text : 'ok',
callback : function (dialog) {
dialog.Close ();
}
}
]
});
};
ImporterApp.prototype.Generate = function (progressBar)
{
function ShowMeshes (importerApp, progressBar, merge)
{
importerApp.inGenerate = true;
var environment = new JSM.AsyncEnvironment ({
onStart : function (taskCount) {
progressBar.Init (taskCount);
},
onProcess : function (currentTask) {
progressBar.Step (currentTask + 1);
},
onFinish : function () {
importerApp.GenerateMenu ();
importerApp.inGenerate = false;
}
});
if (merge) {
var jsonData = importerApp.viewer.GetJsonData ();
importerApp.viewer.SetJsonData (JSM.MergeJsonDataMeshes (jsonData));
}
importerApp.viewer.ShowAllMeshes (environment);
}
var jsonData = this.viewer.GetJsonData ();
if (jsonData.materials.length === 0 || jsonData.meshes.length === 0) {
this.GenerateError ('Failed to open file. Maybe something is wrong with your file.');
return;
}
var myThis = this;
if (jsonData.meshes.length > 250) {
this.dialog.Open ({
title : 'Information',
text : 'The model contains a large number of meshes. It can cause performance problems. Would you like to merge meshes?
',
buttons : [
{
text : 'yes',
callback : function (dialog) {
ShowMeshes (myThis, progressBar, true);
dialog.Close ();
}
},
{
text : 'no',
callback : function (dialog) {
ShowMeshes (myThis, progressBar, false);
dialog.Close ();
}
}
]
});
} else {
ShowMeshes (myThis, progressBar, false);
}
};
ImporterApp.prototype.FitInWindow = function ()
{
this.viewer.FitInWindow ();
};
ImporterApp.prototype.SetFixUp = function ()
{
this.viewer.SetFixUp ();
};
ImporterApp.prototype.SetNamedView = function (viewName)
{
this.viewer.SetNamedView (viewName);
};
ImporterApp.prototype.SetView = function (viewType)
{
this.viewer.SetView (viewType);
};
ImporterApp.prototype.ShowHideMesh = function (meshIndex)
{
this.meshVisibility[meshIndex] = !this.meshVisibility[meshIndex];
if (this.meshVisibility[meshIndex]) {
this.viewer.ShowMesh (meshIndex);
} else {
this.viewer.HideMesh (meshIndex);
}
return this.meshVisibility[meshIndex];
};
ImporterApp.prototype.ProcessFiles = function (fileList)
{
this.dialog.Close ();
if (this.inGenerate) {
return;
}
var userFiles = fileList;
if (userFiles.length === 0) {
return;
}
this.fileNames = null;
var myThis = this;
JSM.ConvertFileListToJsonData (userFiles, {
onError : function () {
myThis.GenerateError ('No readable file found. You can open 3ds, obj and stl files.');
return;
},
onReady : function (fileNames, jsonData) {
myThis.fileNames = fileNames;
myThis.viewer.SetJsonData (jsonData);
var menu = document.getElementById ('menu');
var progressBar = new ImporterProgressBar (menu);
myThis.JsonLoaded (progressBar);
}
});
};
ImporterApp.prototype.DragOver = function (event)
{
event.stopPropagation ();
event.preventDefault ();
event.dataTransfer.dropEffect = 'copy';
};
ImporterApp.prototype.Drop = function (event)
{
event.stopPropagation ();
event.preventDefault ();
this.ProcessFiles (event.dataTransfer.files);
};
ImporterApp.prototype.FileSelected = function (event)
{
event.stopPropagation ();
event.preventDefault ();
this.ProcessFiles (event.target.files);
};
ImporterApp.prototype.OpenFile = function ()
{
var fileInput = document.getElementById('file');
fileInput.click ();
};
window.onload = function ()
{
var importerApp = new ImporterApp ();
importerApp.Init ();
};