diff --git a/.gitignore b/.gitignore
index a7c0acc3..06a311c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ build/*
plugins/*
node_modules
__pycache__
+.DS_Store
diff --git a/assets/icons/download.svg b/assets/icons/download.svg
index 03716d38..087d946b 100644
--- a/assets/icons/download.svg
+++ b/assets/icons/download.svg
@@ -1,4 +1,4 @@
-
+
diff --git a/package-lock.json b/package-lock.json
index 96585b0c..64d532f4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "online-3d-viewer",
- "version": "0.15.0",
+ "version": "0.16.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "online-3d-viewer",
- "version": "0.15.0",
+ "version": "0.16.0",
"license": "MIT",
"dependencies": {
"@simonwep/pickr": "1.9.0",
diff --git a/source/engine/Release/occt-import-js.js b/source/engine/Release/occt-import-js.js
new file mode 100644
index 00000000..1c941f29
--- /dev/null
+++ b/source/engine/Release/occt-import-js.js
@@ -0,0 +1,2 @@
+var occtimportjs=(()=>{var _scriptName=globalThis.document?.currentScript?.src;return async function(moduleArg={}){var moduleRtn;var Module=moduleArg;var ENVIRONMENT_IS_WEB=!!globalThis.window;var ENVIRONMENT_IS_WORKER=!!globalThis.WorkerGlobalScope;var ENVIRONMENT_IS_NODE=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};if(typeof __filename!="undefined"){_scriptName=__filename}else if(ENVIRONMENT_IS_WORKER){_scriptName=self.location.href}var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{if(isFileURI(url)){return new Promise((resolve,reject)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){resolve(xhr.response);return}reject(xhr.status)};xhr.onerror=reject;xhr.send(null)})}var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var EXITSTATUS;var isFileURI=filename=>filename.startsWith("file://");var readyPromiseResolve,readyPromiseReject;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;var HEAP64,HEAPU64;var runtimeInitialized=false;function updateMemoryViews(){var b=wasmMemory.buffer;HEAP8=new Int8Array(b);HEAP16=new Int16Array(b);HEAPU8=new Uint8Array(b);HEAPU16=new Uint16Array(b);HEAP32=new Int32Array(b);HEAPU32=new Uint32Array(b);HEAPF32=new Float32Array(b);HEAPF64=new Float64Array(b);HEAP64=new BigInt64Array(b);HEAPU64=new BigUint64Array(b)}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.initialized)FS.init();TTY.init();wasmExports["X"]();FS.ignorePermissions=false}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(onPostRuns)}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";if(runtimeInitialized){___trap()}var e=new WebAssembly.RuntimeError(what);readyPromiseReject?.(e);throw e}var wasmBinaryFile;function findWasmBinary(){return locateFile("occt-import-js.wasm")}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){return new Promise((resolve,reject)=>{Module["instantiateWasm"](info,(inst,mod)=>{resolve(receiveInstance(inst,mod))})})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var addOnPostRun=cb=>onPostRuns.push(cb);var onPreRuns=[];var addOnPreRun=cb=>onPreRuns.push(cb);var noExitRuntime=true;var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.slice(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.slice(0,-1)}return root+dir},basename:path=>path&&path.match(/([^\/]+|\/)\/*$/)[1],join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(ENVIRONMENT_IS_NODE){var nodeCrypto=require("crypto");return view=>nodeCrypto.randomFillSync(view)}return view=>crypto.getRandomValues(view)};var randomFill=view=>{(randomFill=initRandomFill())(view)};var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).slice(1);to=PATH_FS.resolve(to).slice(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var intArrayFromString=(stringy,dontAddNull,length)=>{var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array};var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf,0,BUFSIZE)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}}else if(globalThis.window?.prompt){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output?.length>0){err(UTF8ArrayToString(tty.output));tty.output=[]}}}};var zeroMemory=(ptr,size)=>HEAPU8.fill(0,ptr,ptr+size);var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(ptr)zeroMemory(ptr,size);return ptr};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16895,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.atime=node.mtime=node.ctime=Date.now();if(parent){parent.contents[name]=node;parent.atime=parent.mtime=parent.ctime=node.atime}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.atime);attr.mtime=new Date(node.mtime);attr.ctime=new Date(node.ctime);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){for(const key of["mode","atime","mtime","ctime"]){if(attr[key]!=null){node[key]=attr[key]}}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){if(!MEMFS.doesNotExistError){MEMFS.doesNotExistError=new FS.ErrnoError(44);MEMFS.doesNotExistError.stack=""}throw MEMFS.doesNotExistError},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){if(FS.isDir(old_node.mode)){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}FS.hashRemoveNode(new_node)}delete old_node.parent.contents[old_node.name];new_dir.contents[new_name]=old_node;old_node.name=new_name;new_dir.ctime=new_dir.mtime=old_node.parent.ctime=old_node.parent.mtime=Date.now()},unlink(parent,name){delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},readdir(node){return[".","..",...Object.keys(node.contents)]},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var asyncLoad=async url=>{var arrayBuffer=await readAsync(url);return new Uint8Array(arrayBuffer)};var FS_createDataFile=(...args)=>FS.createDataFile(...args);var getUniqueRunDependency=id=>id;var runDependencies=0;var dependenciesFulfilled=null;var removeRunDependency=id=>{runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}};var addRunDependency=id=>{runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)};var preloadPlugins=[];var FS_handledByPreloadPlugin=async(byteArray,fullname)=>{if(typeof Browser!="undefined")Browser.init();for(var plugin of preloadPlugins){if(plugin["canHandle"](fullname)){return plugin["handle"](byteArray,fullname)}}return byteArray};var FS_preloadFile=async(parent,name,url,canRead,canWrite,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);addRunDependency(dep);try{var byteArray=url;if(typeof url=="string"){byteArray=await asyncLoad(url)}byteArray=await FS_handledByPreloadPlugin(byteArray,fullname);preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}}finally{removeRunDependency(dep)}};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{FS_preloadFile(parent,name,url,canRead,canWrite,dontCreateFile,canOwn,preFinish).then(onload).catch(onerror)};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,filesystems:null,syncFSRequests:0,readFiles:{},ErrnoError:class{name="ErrnoError";constructor(errno){this.errno=errno}},FSStream:class{shared={};get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{node_ops={};stream_ops={};readMode=292|73;writeMode=146;mounted=null;constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.rdev=rdev;this.atime=this.mtime=this.ctime=Date.now()}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){if(!path){throw new FS.ErrnoError(44)}opts.follow_mount??=true;if(!PATH.isAbs(path)){path=FS.cwd()+"/"+path}linkloop:for(var nlinks=0;nlinks<40;nlinks++){var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){if(!FS.isDir(dir.mode)){return 54}try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&(512|64)){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},checkOpExists(op,err){if(!op){throw new FS.ErrnoError(err)}return op},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},doSetAttr(stream,node,attr){var setattr=stream?.stream_ops.setattr;var arg=setattr?stream:node;setattr??=node.node_ops.setattr;FS.checkOpExists(setattr,63);setattr(arg,attr)},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name){throw new FS.ErrnoError(28)}if(name==="."||name===".."){throw new FS.ErrnoError(20)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},statfs(path){return FS.statfsNode(FS.lookupPath(path,{follow:true}).node)},statfsStream(stream){return FS.statfsNode(stream.node)},statfsNode(node){var rtn={bsize:4096,frsize:4096,blocks:1e6,bfree:5e5,bavail:5e5,files:FS.nextInode,ffree:FS.nextInode-1,fsid:42,flags:2,namelen:255};if(node.node_ops.statfs){Object.assign(rtn,node.node_ops.statfs(node.mount.opts.root))}return rtn},create(path,mode=438){mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode=511){mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var dir of dirs){if(!dir)continue;if(d||PATH.isAbs(path))d+="/";d+=dir;try{FS.mkdir(d,mode)}catch(e){if(e.errno!=20)throw e}}},mkdev(path,mode,dev){if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink(oldpath,newpath){if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},rename(old_path,new_path){var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name);old_node.parent=new_dir}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir(path){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir(path){var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;var readdir=FS.checkOpExists(node.node_ops.readdir,54);return readdir(node)},unlink(path){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink(path){var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return link.node_ops.readlink(link)},stat(path,dontFollow){var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;var getattr=FS.checkOpExists(node.node_ops.getattr,63);return getattr(node)},fstat(fd){var stream=FS.getStreamChecked(fd);var node=stream.node;var getattr=stream.stream_ops.getattr;var arg=getattr?stream:node;getattr??=node.node_ops.getattr;FS.checkOpExists(getattr,63);return getattr(arg)},lstat(path){return FS.stat(path,true)},doChmod(stream,node,mode,dontFollow){FS.doSetAttr(stream,node,{mode:mode&4095|node.mode&~4095,ctime:Date.now(),dontFollow})},chmod(path,mode,dontFollow){var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}FS.doChmod(null,node,mode,dontFollow)},lchmod(path,mode){FS.chmod(path,mode,true)},fchmod(fd,mode){var stream=FS.getStreamChecked(fd);FS.doChmod(stream,stream.node,mode,false)},doChown(stream,node,dontFollow){FS.doSetAttr(stream,node,{timestamp:Date.now(),dontFollow})},chown(path,uid,gid,dontFollow){var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}FS.doChown(null,node,dontFollow)},lchown(path,uid,gid){FS.chown(path,uid,gid,true)},fchown(fd,uid,gid){var stream=FS.getStreamChecked(fd);FS.doChown(stream,stream.node,false)},doTruncate(stream,node,len){if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}FS.doSetAttr(stream,node,{size:len,timestamp:Date.now()})},truncate(path,len){if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}FS.doTruncate(null,node,len)},ftruncate(fd,len){var stream=FS.getStreamChecked(fd);if(len<0||(stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.doTruncate(stream,stream.node,len)},utime(path,atime,mtime){var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;var setattr=FS.checkOpExists(node.node_ops.setattr,63);setattr(node,{atime,mtime})},open(path,flags,mode=438){if(path===""){throw new FS.ErrnoError(44)}flags=typeof flags=="string"?FS_modeStringToFlags(flags):flags;if(flags&64){mode=mode&4095|32768}else{mode=0}var node;var isDirPath;if(typeof path=="object"){node=path}else{isDirPath=path.endsWith("/");var lookup=FS.lookupPath(path,{follow:!(flags&131072),noent_okay:true});node=lookup.node;path=lookup.path}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else if(isDirPath){throw new FS.ErrnoError(31)}else{node=FS.mknod(path,mode|511,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node,path:FS.getPath(node),flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(created){FS.chmod(node,mode&511)}if(Module["logReadFiles"]&&!(flags&1)){if(!(path in FS.readFiles)){FS.readFiles[path]=1}}return stream},close(stream){if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed(stream){return stream.fd===null},llseek(stream,offset,whence){if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read(stream,buffer,offset,length,position){if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write(stream,buffer,offset,length,position,canOwn){if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},mmap(stream,length,position,prot,flags){if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}if(!length){throw new FS.ErrnoError(28)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync(stream,buffer,offset,length,mmapFlags){if(!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},ioctl(stream,cmd,arg){if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile(path,opts={}){opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){abort(`Invalid encoding type "${opts.encoding}"`)}var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){buf=UTF8ArrayToString(buf)}FS.close(stream);return buf},writeFile(path,data,opts={}){opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){data=new Uint8Array(intArrayFromString(data,true))}if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{abort("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomFill(randomBuffer);randomLeft=randomBuffer.byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16895,73);node.stream_ops={llseek:MEMFS.stream_ops.llseek};node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path},id:fd+1};ret.parent=ret;return ret},readdir(){return Array.from(FS.streams.entries()).filter(([k,v])=>v).map(([k,v])=>k.toString())}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS}},init(input,output,error){FS.initialized=true;input??=Module["stdin"];output??=Module["stdout"];error??=Module["stderr"];FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;for(var stream of FS.streams){if(stream){FS.close(stream)}}},findObject(path,dontResolveLastLink){var ret=FS.analyzePath(path,dontResolveLastLink);if(!ret.exists){return null}return ret.object},analyzePath(path,dontResolveLastLink){try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath(parent,path,canRead,canWrite){parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){if(e.errno!=20)throw e}parent=current}return current},createFile(parent,name,properties,canRead,canWrite){var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile(parent,name,data,canRead,canWrite,canOwn){var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS_getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){if(typeof data=="string"){var arr=new Array(data.length);for(var i=0,len=data.length;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))abort("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)abort("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)abort("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))abort("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")abort("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(globalThis.XMLHttpRequest){if(!ENVIRONMENT_IS_WORKER)abort("Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc");var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return dir+"/"+path},writeStat(buf,stat){HEAPU32[buf>>2]=stat.dev;HEAPU32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAPU32[buf+12>>2]=stat.uid;HEAPU32[buf+16>>2]=stat.gid;HEAPU32[buf+20>>2]=stat.rdev;HEAP64[buf+24>>3]=BigInt(stat.size);HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();HEAP64[buf+40>>3]=BigInt(Math.floor(atime/1e3));HEAPU32[buf+48>>2]=atime%1e3*1e3*1e3;HEAP64[buf+56>>3]=BigInt(Math.floor(mtime/1e3));HEAPU32[buf+64>>2]=mtime%1e3*1e3*1e3;HEAP64[buf+72>>3]=BigInt(Math.floor(ctime/1e3));HEAPU32[buf+80>>2]=ctime%1e3*1e3*1e3;HEAP64[buf+88>>3]=BigInt(stat.ino);return 0},writeStatFs(buf,stats){HEAPU32[buf+4>>2]=stats.bsize;HEAPU32[buf+60>>2]=stats.bsize;HEAP64[buf+8>>3]=BigInt(stats.blocks);HEAP64[buf+16>>3]=BigInt(stats.bfree);HEAP64[buf+24>>3]=BigInt(stats.bavail);HEAP64[buf+32>>3]=BigInt(stats.files);HEAP64[buf+40>>3]=BigInt(stats.ffree);HEAPU32[buf+48>>2]=stats.fsid;HEAPU32[buf+64>>2]=stats.flags;HEAPU32[buf+56>>2]=stats.namelen},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_chmod(path,mode){try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var syscallGetVarargI=()=>{var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret};var syscallGetVarargP=syscallGetVarargI;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fstat64(fd,buf){try{return SYSCALLS.writeStat(buf,FS.fstat(fd))}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>2]=termios.c_iflag||0;HEAP32[argp+4>>2]=termios.c_oflag||0;HEAP32[argp+8>>2]=termios.c_cflag||0;HEAP32[argp+12>>2]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>2];var c_oflag=HEAP32[argp+4>>2];var c_cflag=HEAP32[argp+8>>2];var c_lflag=HEAP32[argp+12>>2];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag,c_oflag,c_cflag,c_lflag,c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21537:case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>1]=winsize[0];HEAP16[argp+2>>1]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_lstat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.writeStat(buf,FS.lstat(path))}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_newfstatat(dirfd,path,buf,flags){try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.writeStat(buf,nofollow?FS.lstat(path):FS.stat(path))}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_rmdir(path){try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.writeStat(buf,FS.stat(path))}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_unlinkat(dirfd,path,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(!flags){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{return-28}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __abort_js=()=>abort("");var AsciiToString=ptr=>{var str="";while(1){var ch=HEAPU8[ptr++];if(!ch)return str;str+=String.fromCharCode(ch)}};var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var BindingError=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};var throwBindingError=message=>{throw new BindingError(message)};function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){return sharedRegisterType(rawType,registeredInstance,options)}var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>HEAP8[pointer]:pointer=>HEAPU8[pointer];case 2:return signed?pointer=>HEAP16[pointer>>1]:pointer=>HEAPU16[pointer>>1];case 4:return signed?pointer=>HEAP32[pointer>>2]:pointer=>HEAPU32[pointer>>2];case 8:return signed?pointer=>HEAP64[pointer>>3]:pointer=>HEAPU64[pointer>>3];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_bigint=(primitiveType,name,size,minRange,maxRange)=>{name=AsciiToString(name);const isUnsignedType=minRange===0n;let fromWireType=value=>value;if(isUnsignedType){const bitSize=size*8;fromWireType=value=>BigInt.asUintN(bitSize,value);maxRange=fromWireType(maxRange)}registerType(primitiveType,{name,fromWireType,toWireType:(destructors,value)=>{if(typeof value=="number"){value=BigInt(value)}return value},readValueFromPointer:integerReadValueFromPointer(name,size,!isUnsignedType),destructorFunction:null})};var __embind_register_bool=(rawType,name,trueValue,falseValue)=>{name=AsciiToString(name);registerType(rawType,{name,fromWireType:function(wt){return!!wt},toWireType:function(destructors,o){return o?trueValue:falseValue},readValueFromPointer:function(pointer){return this.fromWireType(HEAPU8[pointer])},destructorFunction:null})};var emval_freelist=[];var emval_handles=[0,1,,1,null,1,true,1,false,1];var __emval_decref=handle=>{if(handle>9&&0===--emval_handles[handle+1]){emval_handles[handle]=undefined;emval_freelist.push(handle)}};var Emval={toValue:handle=>{if(!handle){throwBindingError(`Cannot use deleted val. handle = ${handle}`)}return emval_handles[handle]},toHandle:value=>{switch(value){case undefined:return 2;case null:return 4;case true:return 6;case false:return 8;default:{const handle=emval_freelist.pop()||emval_handles.length;emval_handles[handle]=value;emval_handles[handle+1]=1;return handle}}}};function readPointer(pointer){return this.fromWireType(HEAPU32[pointer>>2])}var EmValType={name:"emscripten::val",fromWireType:handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},toWireType:(destructors,value)=>Emval.toHandle(value),readValueFromPointer:readPointer,destructorFunction:null};var __embind_register_emval=rawType=>registerType(rawType,EmValType);var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this.fromWireType(HEAPF32[pointer>>2])};case 8:return function(pointer){return this.fromWireType(HEAPF64[pointer>>3])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=(rawType,name,size)=>{name=AsciiToString(name);registerType(rawType,{name,fromWireType:value=>value,toWireType:(destructors,value)=>value,readValueFromPointer:floatReadValueFromPointer(name,size),destructorFunction:null})};var createNamedFunction=(name,func)=>Object.defineProperty(func,"name",{value:name});var runDestructors=destructors=>{while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}};function usesDestructorStack(argTypes){for(var i=1;i{if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(...args){if(!proto[methodName].overloadTable.hasOwnProperty(args.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[args.length].apply(this,args)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}};var exposePublicSymbol=(name,value,numArguments)=>{if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module[name].overloadTable.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var heap32VectorToArray=(count,firstElement)=>{var array=[];for(var i=0;i>2])}return array};var InternalError=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};var throwInternalError=message=>{throw new InternalError(message)};var replacePublicSymbol=(name,value,numArguments)=>{if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistent public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var wasmTableMirror=[];var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};var embind__requireFunction=(signature,rawFunction,isAsync=false)=>{signature=AsciiToString(signature);function makeDynCaller(){var rtn=getWasmTableEntry(rawFunction);return rtn}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp};class UnboundTypeError extends Error{}var getTypeName=type=>{var ptr=___getTypeName(type);var rv=AsciiToString(ptr);_free(ptr);return rv};var throwUnboundTypeError=(message,types)=>{var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))};var whenDependentTypesAreResolved=(myTypes,dependentTypes,getTypeConverters)=>{myTypes.forEach(type=>typeDependencies[type]=dependentTypes);function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}};var getFunctionName=signature=>{signature=signature.trim();const argsIndex=signature.indexOf("(");if(argsIndex===-1)return signature;return signature.slice(0,argsIndex)};var __embind_register_function=(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync,isNonnullReturn)=>{var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=AsciiToString(name);name=getFunctionName(name);rawInvoker=embind__requireFunction(signature,rawInvoker,isAsync);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,argTypes=>{var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})};var __embind_register_integer=(primitiveType,name,size,minRange,maxRange)=>{name=AsciiToString(name);const isUnsignedType=minRange===0;let fromWireType=value=>value;if(isUnsignedType){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift;maxRange=fromWireType(maxRange)}registerType(primitiveType,{name,fromWireType,toWireType:(destructors,value)=>value,readValueFromPointer:integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})};var __embind_register_memory_view=(rawType,dataTypeIndex,name)=>{var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,BigInt64Array,BigUint64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=HEAPU32[handle>>2];var data=HEAPU32[handle+4>>2];return new TA(HEAP8.buffer,data,size)}name=AsciiToString(name);registerType(rawType,{name,fromWireType:decodeMemoryView,readValueFromPointer:decodeMemoryView},{ignoreDuplicateRegistrations:true})};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var __embind_register_std_string=(rawType,name)=>{name=AsciiToString(name);var stdStringIsUTF8=true;registerType(rawType,{name,fromWireType(value){var length=HEAPU32[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){str=UTF8ToString(payload,length,true)}else{str="";for(var i=0;i>2]=length;if(valueIsOfTypeString){if(stdStringIsUTF8){stringToUTF8(value,ptr,length+1)}else{for(var i=0;i255){_free(base);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i]=charCode}}}else{HEAPU8.set(value,ptr)}if(destructors!==null){destructors.push(_free,base)}return base},readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})};var UTF16Decoder=globalThis.TextDecoder?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead,ignoreNul)=>{var idx=ptr>>1;var endIdx=findStringEnd(HEAPU16,idx,maxBytesToRead/2,ignoreNul);if(endIdx-idx>16&&UTF16Decoder)return UTF16Decoder.decode(HEAPU16.subarray(idx,endIdx));var str="";for(var i=idx;i{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead,ignoreNul)=>{var str="";var startIdx=ptr>>2;for(var i=0;!(i>=maxBytesToRead/4);i++){var utf32=HEAPU32[startIdx+i];if(!utf32&&!ignoreNul)break;str+=String.fromCodePoint(utf32)}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i65535){i++}HEAP32[outPtr>>2]=codePoint;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i65535){i++}len+=4}return len};var __embind_register_std_wstring=(rawType,charSize,name)=>{name=AsciiToString(name);var decodeString,encodeString,lengthBytesUTF;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16}else{decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32}registerType(rawType,{name,fromWireType:value=>{var length=HEAPU32[value>>2];var str=decodeString(value+4,length*charSize,true);_free(value);return str},toWireType:(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length/charSize;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})};var __embind_register_void=(rawType,name)=>{name=AsciiToString(name);registerType(rawType,{isVoid:true,name,fromWireType:()=>undefined,toWireType:(destructors,o)=>undefined})};var inetPton4=str=>{var b=str.split(".");for(var i=0;i<4;i++){var tmp=Number(b[i]);if(isNaN(tmp))return null;b[i]=tmp}return(b[0]|b[1]<<8|b[2]<<16|b[3]<<24)>>>0};var inetPton6=str=>{var words;var w,offset,z;var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;var parts=[];if(!valid6regx.test(str)){return null}if(str==="::"){return[0,0,0,0,0,0,0,0]}if(str.startsWith("::")){str=str.replace("::","Z:")}else{str=str.replace("::",":Z:")}if(str.indexOf(".")>0){str=str.replace(new RegExp("[.]","g"),":");words=str.split(":");words[words.length-4]=Number(words[words.length-4])+Number(words[words.length-3])*256;words[words.length-3]=Number(words[words.length-2])+Number(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w{var nameString=UTF8ToString(name);return inetPton4(DNS.lookup_name(nameString))};var emval_methodCallers=[];var emval_addMethodCaller=caller=>{var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id};var requireRegisteredType=(rawType,humanName)=>{var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`)}return impl};var emval_lookupTypes=(argCount,argTypes)=>{var a=new Array(argCount);for(var i=0;i>2],`parameter ${i}`)}return a};var emval_returnValue=(toReturnWire,destructorsRef,handle)=>{var destructors=[];var result=toReturnWire(destructors,handle);if(destructors.length){HEAPU32[destructorsRef>>2]=Emval.toHandle(destructors)}return result};var emval_symbols={};var getStringOrSymbol=address=>{var symbol=emval_symbols[address];if(symbol===undefined){return AsciiToString(address)}return symbol};var __emval_create_invoker=(argCount,argTypesPtr,kind)=>{var GenericWireTypeSize=8;var[retType,...argTypes]=emval_lookupTypes(argCount,argTypesPtr);var toReturnWire=retType.toWireType.bind(retType);var argFromPtr=argTypes.map(type=>type.readValueFromPointer.bind(type));argCount--;var captures={toValue:Emval.toValue};var args=argFromPtr.map((argFromPtr,i)=>{var captureName=`argFromPtr${i}`;captures[captureName]=argFromPtr;return`${captureName}(args${i?"+"+i*GenericWireTypeSize:""})`});var functionBody;switch(kind){case 0:functionBody="toValue(handle)";break;case 2:functionBody="new (toValue(handle))";break;case 3:functionBody="";break;case 1:captures["getStringOrSymbol"]=getStringOrSymbol;functionBody="toValue(handle)[getStringOrSymbol(methodName)]";break}functionBody+=`(${args})`;if(!retType.isVoid){captures["toReturnWire"]=toReturnWire;captures["emval_returnValue"]=emval_returnValue;functionBody=`return emval_returnValue(toReturnWire, destructorsRef, ${functionBody})`}functionBody=`return function (handle, methodName, destructorsRef, args) {\n ${functionBody}\n }`;var invokerFunction=new Function(Object.keys(captures),functionBody)(...Object.values(captures));var functionName=`methodCaller<(${argTypes.map(t=>t.name)}) => ${retType.name}>`;return emval_addMethodCaller(createNamedFunction(functionName,invokerFunction))};var __emval_get_global=name=>{if(!name){return Emval.toHandle(globalThis)}name=getStringOrSymbol(name);return Emval.toHandle(globalThis[name])};var __emval_get_property=(handle,key)=>{handle=Emval.toValue(handle);key=Emval.toValue(key);return Emval.toHandle(handle[key])};var __emval_incref=handle=>{if(handle>9){emval_handles[handle+1]+=1}};var __emval_invoke=(caller,handle,methodName,destructorsRef,args)=>emval_methodCallers[caller](handle,methodName,destructorsRef,args);var __emval_new_array=()=>Emval.toHandle([]);var __emval_new_cstring=v=>Emval.toHandle(getStringOrSymbol(v));var __emval_new_object=()=>Emval.toHandle({});var __emval_run_destructors=handle=>{var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)};var __emval_set_property=(handle,key,value)=>{handle=Emval.toValue(handle);key=Emval.toValue(key);value=Emval.toValue(value);handle[key]=value};var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};var INT53_MAX=9007199254740992;var INT53_MIN=-9007199254740992;var bigintToI53Checked=num=>numINT53_MAX?NaN:Number(num);function __localtime_js(time,tmPtr){time=bigintToI53Checked(time);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst}var __tzset_js=(timezone,daylight,std_name,dst_name)=>{var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);var extractZone=timezoneOffset=>{var sign=timezoneOffset>=0?"-":"+";var absOffset=Math.abs(timezoneOffset);var hours=String(Math.floor(absOffset/60)).padStart(2,"0");var minutes=String(absOffset%60).padStart(2,"0");return`UTC${sign}${hours}${minutes}`};var winterName=extractZone(winterOffset);var summerName=extractZone(summerOffset);if(summerOffsetperformance.now();var _emscripten_date_now=()=>Date.now();var nowIsMonotonic=1;var checkWasiClock=clock_id=>clock_id>=0&&clock_id<=3;function _clock_time_get(clk_id,ignored_precision,ptime){ignored_precision=bigintToI53Checked(ignored_precision);if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=_emscripten_date_now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);HEAP64[ptime>>3]=BigInt(nsec);return 0}var jsStackTrace=()=>(new Error).stack.toString();var getCallstack=flags=>{var callstack=jsStackTrace();var lines=callstack.split("\n");callstack="";var firefoxRe=new RegExp("\\s*(.*?)@(.*?):([0-9]+):([0-9]+)");var chromeRe=new RegExp("\\s*at (.*?) \\((.*):(.*):(.*)\\)");for(var line of lines){var symbolName="";var file="";var lineno=0;var column=0;var parts=chromeRe.exec(line);if(parts?.length==5){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]}else{parts=firefoxRe.exec(line);if(parts?.length>=4){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]|0}else{callstack+=line+"\n";continue}}if(symbolName=="_emscripten_log"||symbolName=="_emscripten_get_callstack"){callstack="";continue}if(flags&24){if(flags&64){file=file.substring(file.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=` at ${symbolName} (${file}:${lineno}:${column})\n`}}callstack=callstack.replace(/\s+$/,"");return callstack};var _emscripten_get_callstack=(flags,str,maxbytes)=>{var callstack=getCallstack(flags);if(!str||maxbytes<=0){return lengthBytesUTF8(callstack)+1}var bytesWrittenExcludingNull=stringToUTF8(callstack,str,maxbytes);return bytesWrittenExcludingNull+1};var getHeapMax=()=>2147483648;var _emscripten_get_heap_max=()=>getHeapMax();var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.language||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var _environ_get=(__environ,environ_buf)=>{var bufSize=0;var envp=0;for(var string of getEnvStrings()){var ptr=environ_buf+bufSize;HEAPU32[__environ+envp>>2]=ptr;bufSize+=stringToUTF8(string,ptr,Infinity)+1;envp+=4}return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;for(var string of strings){bufSize+=lengthBytesUTF8(string)+1}HEAPU32[penviron_buf_size>>2]=bufSize;return 0};var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var _exit=exitJS;function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset,whence,newOffset){offset=bigintToI53Checked(offset);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);HEAP64[newOffset>>3]=BigInt(stream.position);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}FS.createPreloadedFile=FS_createPreloadedFile;FS.preloadFile=FS_preloadFile;FS.staticInit();{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["preloadPlugins"])preloadPlugins=Module["preloadPlugins"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].shift()()}}}var ___getTypeName,_malloc,_free,_htons,_emscripten_builtin_memalign,___trap,memory,__indirect_function_table,wasmMemory,wasmTable;function assignWasmExports(wasmExports){___getTypeName=wasmExports["Y"];_malloc=wasmExports["_"];_free=wasmExports["$"];_htons=wasmExports["aa"];_emscripten_builtin_memalign=wasmExports["ba"];___trap=wasmExports["ca"];memory=wasmMemory=wasmExports["W"];__indirect_function_table=wasmTable=wasmExports["Z"]}var wasmImports={I:___syscall_chmod,J:___syscall_faccessat,h:___syscall_fcntl64,F:___syscall_fstat64,M:___syscall_ioctl,C:___syscall_lstat64,D:___syscall_newfstatat,j:___syscall_openat,v:___syscall_rmdir,E:___syscall_stat64,w:___syscall_unlinkat,u:__abort_js,n:__embind_register_bigint,S:__embind_register_bool,Q:__embind_register_emval,m:__embind_register_float,f:__embind_register_function,d:__embind_register_integer,a:__embind_register_memory_view,R:__embind_register_std_string,i:__embind_register_std_wstring,T:__embind_register_void,r:__emscripten_lookup_name,c:__emval_create_invoker,P:__emval_decref,z:__emval_get_global,k:__emval_get_property,o:__emval_incref,b:__emval_invoke,U:__emval_new_array,q:__emval_new_cstring,V:__emval_new_object,p:__emval_run_destructors,e:__emval_set_property,x:__localtime_js,K:__tzset_js,H:_clock_time_get,G:_emscripten_date_now,N:_emscripten_get_callstack,t:_emscripten_get_heap_max,s:_emscripten_resize_heap,A:_environ_get,B:_environ_sizes_get,O:_exit,g:_fd_close,L:_fd_read,y:_fd_seek,l:_fd_write};function run(){if(runDependencies>0){dependenciesFulfilled=run;return}preRun();if(runDependencies>0){dependenciesFulfilled=run;return}function doRun(){Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve?.(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}var wasmExports;wasmExports=await (createWasm());run();if(runtimeInitialized){moduleRtn=Module}else{moduleRtn=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject})}
+;return moduleRtn}})();if(typeof exports==="object"&&typeof module==="object"){module.exports=occtimportjs;module.exports.default=occtimportjs}else if(typeof define==="function"&&define["amd"])define([],()=>occtimportjs);
diff --git a/source/engine/Release/occt-import-js.wasm b/source/engine/Release/occt-import-js.wasm
new file mode 100755
index 00000000..4c73b602
Binary files /dev/null and b/source/engine/Release/occt-import-js.wasm differ
diff --git a/source/engine/viewer/viewer.js b/source/engine/viewer/viewer.js
index 789c01d0..0e11e4e7 100644
--- a/source/engine/viewer/viewer.js
+++ b/source/engine/viewer/viewer.js
@@ -10,51 +10,48 @@ import { ViewerModel, ViewerMainModel } from './viewermodel.js';
import * as THREE from 'three';
-export function GetDefaultCamera (direction)
-{
+export function GetDefaultCamera(direction) {
let fieldOfView = 45.0;
if (direction === Direction.X) {
- return new Camera (
- new Coord3D (2.0, -3.0, 1.5),
- new Coord3D (0.0, 0.0, 0.0),
- new Coord3D (1.0, 0.0, 0.0),
+ return new Camera(
+ new Coord3D(2.0, -3.0, 1.5),
+ new Coord3D(0.0, 0.0, 0.0),
+ new Coord3D(1.0, 0.0, 0.0),
fieldOfView
);
} else if (direction === Direction.Y) {
- return new Camera (
- new Coord3D (-1.5, 2.0, 3.0),
- new Coord3D (0.0, 0.0, 0.0),
- new Coord3D (0.0, 1.0, 0.0),
+ return new Camera(
+ new Coord3D(-1.5, 2.0, 3.0),
+ new Coord3D(0.0, 0.0, 0.0),
+ new Coord3D(0.0, 1.0, 0.0),
fieldOfView
);
} else if (direction === Direction.Z) {
- return new Camera (
- new Coord3D (-1.5, -3.0, 2.0),
- new Coord3D (0.0, 0.0, 0.0),
- new Coord3D (0.0, 0.0, 1.0),
+ return new Camera(
+ new Coord3D(-1.5, -3.0, 2.0),
+ new Coord3D(0.0, 0.0, 0.0),
+ new Coord3D(0.0, 0.0, 1.0),
fieldOfView
);
}
return null;
}
-export function TraverseThreeObject (object, processor)
-{
- if (!processor (object)) {
+export function TraverseThreeObject(object, processor) {
+ if (!processor(object)) {
return false;
}
for (let child of object.children) {
- if (!TraverseThreeObject (child, processor)) {
+ if (!TraverseThreeObject(child, processor)) {
return false;
}
}
return true;
}
-export function GetShadingTypeOfObject (mainObject)
-{
+export function GetShadingTypeOfObject(mainObject) {
let shadingType = null;
- TraverseThreeObject (mainObject, (obj) => {
+ TraverseThreeObject(mainObject, (obj) => {
if (obj.isMesh) {
for (const material of obj.material) {
if (material.type === 'MeshPhongMaterial') {
@@ -70,21 +67,17 @@ export function GetShadingTypeOfObject (mainObject)
return shadingType;
}
-export class CameraValidator
-{
- constructor ()
- {
+export class CameraValidator {
+ constructor() {
this.eyeCenterDistance = 0.0;
this.forceUpdate = true;
}
- ForceUpdate ()
- {
+ ForceUpdate() {
this.forceUpdate = true;
}
- ValidatePerspective ()
- {
+ ValidatePerspective() {
if (this.forceUpdate) {
this.forceUpdate = false;
return false;
@@ -92,9 +85,8 @@ export class CameraValidator
return true;
}
- ValidateOrthographic (eyeCenterDistance)
- {
- if (this.forceUpdate || !IsEqual (this.eyeCenterDistance, eyeCenterDistance)) {
+ ValidateOrthographic(eyeCenterDistance) {
+ if (this.forceUpdate || !IsEqual(this.eyeCenterDistance, eyeCenterDistance)) {
this.eyeCenterDistance = eyeCenterDistance;
this.forceUpdate = false;
return false;
@@ -103,62 +95,55 @@ export class CameraValidator
}
}
-export class UpVector
-{
- constructor ()
- {
+export class UpVector {
+ constructor() {
this.direction = Direction.Y;
this.isFixed = true;
this.isFlipped = false;
}
- SetDirection (newDirection, oldCamera)
- {
+ SetDirection(newDirection, oldCamera) {
this.direction = newDirection;
this.isFlipped = false;
- let defaultCamera = GetDefaultCamera (this.direction);
- let defaultDir = SubCoord3D (defaultCamera.eye, defaultCamera.center);
+ let defaultCamera = GetDefaultCamera(this.direction);
+ let defaultDir = SubCoord3D(defaultCamera.eye, defaultCamera.center);
- let distance = CoordDistance3D (oldCamera.center, oldCamera.eye);
- let newEye = oldCamera.center.Clone ().Offset (defaultDir, distance);
+ let distance = CoordDistance3D(oldCamera.center, oldCamera.eye);
+ let newEye = oldCamera.center.Clone().Offset(defaultDir, distance);
- let newCamera = oldCamera.Clone ();
+ let newCamera = oldCamera.Clone();
if (this.direction === Direction.X) {
- newCamera.up = new Coord3D (1.0, 0.0, 0.0);
+ newCamera.up = new Coord3D(1.0, 0.0, 0.0);
newCamera.eye = newEye;
} else if (this.direction === Direction.Y) {
- newCamera.up = new Coord3D (0.0, 1.0, 0.0);
+ newCamera.up = new Coord3D(0.0, 1.0, 0.0);
newCamera.eye = newEye;
} else if (this.direction === Direction.Z) {
- newCamera.up = new Coord3D (0.0, 0.0, 1.0);
+ newCamera.up = new Coord3D(0.0, 0.0, 1.0);
newCamera.eye = newEye;
}
return newCamera;
}
- SetFixed (isFixed, oldCamera)
- {
+ SetFixed(isFixed, oldCamera) {
this.isFixed = isFixed;
if (this.isFixed) {
- return this.SetDirection (this.direction, oldCamera);
+ return this.SetDirection(this.direction, oldCamera);
}
return null;
}
- Flip (oldCamera)
- {
+ Flip(oldCamera) {
this.isFlipped = !this.isFlipped;
- let newCamera = oldCamera.Clone ();
- newCamera.up.MultiplyScalar (-1.0);
+ let newCamera = oldCamera.Clone();
+ newCamera.up.MultiplyScalar(-1.0);
return newCamera;
}
}
-export class Viewer
-{
- constructor ()
- {
+export class Viewer {
+ constructor() {
THREE.ColorManagement.enabled = false;
this.canvas = null;
@@ -173,165 +158,148 @@ export class Viewer
this.navigation = null;
this.upVector = null;
this.settings = {
- animationSteps : 40
+ animationSteps: 40
};
}
- Init (canvas)
- {
+ Init(canvas) {
this.canvas = canvas;
this.canvas.id = 'viewer';
let parameters = {
- canvas : this.canvas,
- antialias : true
+ canvas: this.canvas,
+ antialias: true
};
- this.renderer = new THREE.WebGLRenderer (parameters);
+ this.renderer = new THREE.WebGLRenderer(parameters);
this.renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
if (window.devicePixelRatio) {
- this.renderer.setPixelRatio (window.devicePixelRatio);
+ this.renderer.setPixelRatio(window.devicePixelRatio);
}
- this.renderer.setClearColor ('#ffffff', 1.0);
- this.renderer.setSize (this.canvas.width, this.canvas.height);
+ this.renderer.setClearColor('#ffffff', 1.0);
+ this.renderer.setSize(this.canvas.width, this.canvas.height);
- this.scene = new THREE.Scene ();
- this.mainModel = new ViewerMainModel (this.scene);
- this.extraModel = new ViewerModel (this.scene);
+ this.scene = new THREE.Scene();
+ this.mainModel = new ViewerMainModel(this.scene);
+ this.extraModel = new ViewerModel(this.scene);
- this.InitNavigation ();
- this.InitShading ();
+ this.InitNavigation();
+ this.InitShading();
- this.Render ();
+ this.Render();
}
- SetMouseClickHandler (onMouseClick)
- {
- this.navigation.SetMouseClickHandler (onMouseClick);
+ SetMouseClickHandler(onMouseClick) {
+ this.navigation.SetMouseClickHandler(onMouseClick);
}
- SetMouseMoveHandler (onMouseMove)
- {
- this.navigation.SetMouseMoveHandler (onMouseMove);
+ SetMouseMoveHandler(onMouseMove) {
+ this.navigation.SetMouseMoveHandler(onMouseMove);
}
- SetContextMenuHandler (onContext)
- {
- this.navigation.SetContextMenuHandler (onContext);
+ SetContextMenuHandler(onContext) {
+ this.navigation.SetContextMenuHandler(onContext);
}
- SetEdgeSettings (edgeSettings)
- {
- let newEdgeSettings = edgeSettings.Clone ();
- this.mainModel.SetEdgeSettings (newEdgeSettings);
- this.Render ();
+ SetEdgeSettings(edgeSettings) {
+ let newEdgeSettings = edgeSettings.Clone();
+ this.mainModel.SetEdgeSettings(newEdgeSettings);
+ this.Render();
}
- SetEnvironmentMapSettings (environmentSettings)
- {
- let newEnvironmentSettings = environmentSettings.Clone ();
- this.shadingModel.SetEnvironmentMapSettings (newEnvironmentSettings, () => {
- this.Render ();
+ SetEnvironmentMapSettings(environmentSettings) {
+ let newEnvironmentSettings = environmentSettings.Clone();
+ this.shadingModel.SetEnvironmentMapSettings(newEnvironmentSettings, () => {
+ this.Render();
});
- this.shadingModel.UpdateShading ();
- this.Render ();
+ this.shadingModel.UpdateShading();
+ this.Render();
}
- SetBackgroundColor (color)
- {
- let bgColor = new THREE.Color (
- ColorComponentToFloat (color.r),
- ColorComponentToFloat (color.g),
- ColorComponentToFloat (color.b)
+ SetBackgroundColor(color) {
+ let bgColor = new THREE.Color(
+ ColorComponentToFloat(color.r),
+ ColorComponentToFloat(color.g),
+ ColorComponentToFloat(color.b)
);
- let alpha = ColorComponentToFloat (color.a);
- this.renderer.setClearColor (bgColor, alpha);
- this.Render ();
+ let alpha = ColorComponentToFloat(color.a);
+ this.renderer.setClearColor(bgColor, alpha);
+ this.Render();
}
- GetCanvas ()
- {
+ GetCanvas() {
return this.canvas;
}
- GetCamera ()
- {
- return this.navigation.GetCamera ();
+ GetCamera() {
+ return this.navigation.GetCamera();
}
- GetProjectionMode ()
- {
+ GetProjectionMode() {
return this.projectionMode;
}
- SetCamera (camera)
- {
- this.navigation.SetCamera (camera);
- this.cameraValidator.ForceUpdate ();
- this.Render ();
+ SetCamera(camera) {
+ this.navigation.SetCamera(camera);
+ this.cameraValidator.ForceUpdate();
+ this.Render();
}
- SetProjectionMode (projectionMode)
- {
+ SetProjectionMode(projectionMode) {
if (this.projectionMode === projectionMode) {
return;
}
- this.scene.remove (this.camera);
+ this.scene.remove(this.camera);
if (projectionMode === ProjectionMode.Perspective) {
- this.camera = new THREE.PerspectiveCamera (45.0, 1.0, 0.1, 1000.0);
+ this.camera = new THREE.PerspectiveCamera(45.0, 1.0, 0.1, 1000.0);
} else if (projectionMode === ProjectionMode.Orthographic) {
- this.camera = new THREE.OrthographicCamera (-1.0, 1.0, 1.0, -1.0, 0.1, 1000.0);
+ this.camera = new THREE.OrthographicCamera(-1.0, 1.0, 1.0, -1.0, 0.1, 1000.0);
}
- this.scene.add (this.camera);
+ this.scene.add(this.camera);
this.projectionMode = projectionMode;
- this.shadingModel.SetProjectionMode (projectionMode);
- this.cameraValidator.ForceUpdate ();
+ this.shadingModel.SetProjectionMode(projectionMode);
+ this.cameraValidator.ForceUpdate();
- this.AdjustClippingPlanes ();
- this.Render ();
+ this.AdjustClippingPlanes();
+ this.Render();
}
- Resize (width, height)
- {
- let innerSize = GetDomElementInnerDimensions (this.canvas, width, height);
- this.ResizeRenderer (innerSize.width, innerSize.height);
+ Resize(width, height) {
+ let innerSize = GetDomElementInnerDimensions(this.canvas, width, height);
+ this.ResizeRenderer(innerSize.width, innerSize.height);
}
- ResizeRenderer (width, height)
- {
+ ResizeRenderer(width, height) {
if (window.devicePixelRatio) {
- this.renderer.setPixelRatio (window.devicePixelRatio);
+ this.renderer.setPixelRatio(window.devicePixelRatio);
}
- this.renderer.setSize (width, height);
- this.cameraValidator.ForceUpdate ();
- this.Render ();
+ this.renderer.setSize(width, height);
+ this.cameraValidator.ForceUpdate();
+ this.Render();
}
- FitSphereToWindow (boundingSphere, animation)
- {
+ FitSphereToWindow(boundingSphere, animation) {
if (boundingSphere === null) {
return;
}
- let center = new Coord3D (boundingSphere.center.x, boundingSphere.center.y, boundingSphere.center.z);
+ let center = new Coord3D(boundingSphere.center.x, boundingSphere.center.y, boundingSphere.center.z);
let radius = boundingSphere.radius;
- let newCamera = this.navigation.GetFitToSphereCamera (center, radius);
- this.navigation.MoveCamera (newCamera, animation ? this.settings.animationSteps : 0);
+ let newCamera = this.navigation.GetFitToSphereCamera(center, radius);
+ this.navigation.MoveCamera(newCamera, animation ? this.settings.animationSteps : 0);
}
- AdjustClippingPlanes ()
- {
- let boundingSphere = this.GetBoundingSphere ((meshUserData) => {
+ AdjustClippingPlanes() {
+ let boundingSphere = this.GetBoundingSphere((meshUserData) => {
return true;
});
- this.AdjustClippingPlanesToSphere (boundingSphere);
+ this.AdjustClippingPlanesToSphere(boundingSphere);
}
- AdjustClippingPlanesToSphere (boundingSphere)
- {
+ AdjustClippingPlanesToSphere(boundingSphere) {
if (boundingSphere === null) {
return;
}
@@ -349,129 +317,118 @@ export class Viewer
this.camera.far = 1000000.0;
}
- this.cameraValidator.ForceUpdate ();
- this.Render ();
+ this.cameraValidator.ForceUpdate();
+ this.Render();
}
- GetNavigationMode ()
- {
- return this.navigation.GetNavigationMode ();
+ GetNavigationMode() {
+ return this.navigation.GetNavigationMode();
}
- SetNavigationMode (navigationMode)
- {
- let oldCamera = this.navigation.GetCamera ();
- let newCamera = this.upVector.SetFixed (navigationMode === NavigationMode.FixedUpVector, oldCamera);
- this.navigation.SetNavigationMode (navigationMode);
+ SetNavigationMode(navigationMode) {
+ let oldCamera = this.navigation.GetCamera();
+ let newCamera = this.upVector.SetFixed(navigationMode === NavigationMode.FixedUpVector, oldCamera);
+ this.navigation.SetNavigationMode(navigationMode);
if (newCamera !== null) {
- this.navigation.MoveCamera (newCamera, this.settings.animationSteps);
+ this.navigation.MoveCamera(newCamera, this.settings.animationSteps);
}
- this.Render ();
+ this.Render();
}
- SetUpVector (upDirection, animate)
- {
- let oldCamera = this.navigation.GetCamera ();
- let newCamera = this.upVector.SetDirection (upDirection, oldCamera);
+ SetUpVector(upDirection, animate) {
+ let oldCamera = this.navigation.GetCamera();
+ let newCamera = this.upVector.SetDirection(upDirection, oldCamera);
let animationSteps = animate ? this.settings.animationSteps : 0;
- this.navigation.MoveCamera (newCamera, animationSteps);
- this.Render ();
+ this.navigation.MoveCamera(newCamera, animationSteps);
+ this.Render();
}
- FlipUpVector ()
- {
- let oldCamera = this.navigation.GetCamera ();
- let newCamera = this.upVector.Flip (oldCamera);
- this.navigation.MoveCamera (newCamera, 0);
- this.Render ();
+ FlipUpVector() {
+ let oldCamera = this.navigation.GetCamera();
+ let newCamera = this.upVector.Flip(oldCamera);
+ this.navigation.MoveCamera(newCamera, 0);
+ this.Render();
}
- Render ()
- {
- let navigationCamera = this.navigation.GetCamera ();
+ Render() {
+ let navigationCamera = this.navigation.GetCamera();
- this.camera.position.set (navigationCamera.eye.x, navigationCamera.eye.y, navigationCamera.eye.z);
- this.camera.up.set (navigationCamera.up.x, navigationCamera.up.y, navigationCamera.up.z);
- this.camera.lookAt (new THREE.Vector3 (navigationCamera.center.x, navigationCamera.center.y, navigationCamera.center.z));
+ this.camera.position.set(navigationCamera.eye.x, navigationCamera.eye.y, navigationCamera.eye.z);
+ this.camera.up.set(navigationCamera.up.x, navigationCamera.up.y, navigationCamera.up.z);
+ this.camera.lookAt(new THREE.Vector3(navigationCamera.center.x, navigationCamera.center.y, navigationCamera.center.z));
if (this.projectionMode === ProjectionMode.Perspective) {
- if (!this.cameraValidator.ValidatePerspective ()) {
+ if (!this.cameraValidator.ValidatePerspective()) {
this.camera.aspect = this.canvas.width / this.canvas.height;
this.camera.fov = navigationCamera.fov;
- this.camera.updateProjectionMatrix ();
+ this.camera.updateProjectionMatrix();
}
} else if (this.projectionMode === ProjectionMode.Orthographic) {
- let eyeCenterDistance = CoordDistance3D (navigationCamera.eye, navigationCamera.center);
- if (!this.cameraValidator.ValidateOrthographic (eyeCenterDistance)) {
+ let eyeCenterDistance = CoordDistance3D(navigationCamera.eye, navigationCamera.center);
+ if (!this.cameraValidator.ValidateOrthographic(eyeCenterDistance)) {
let aspect = this.canvas.width / this.canvas.height;
- let eyeCenterDistance = CoordDistance3D (navigationCamera.eye, navigationCamera.center);
- let frustumHalfHeight = eyeCenterDistance * Math.tan (0.5 * navigationCamera.fov * DegRad);
+ let eyeCenterDistance = CoordDistance3D(navigationCamera.eye, navigationCamera.center);
+ let frustumHalfHeight = eyeCenterDistance * Math.tan(0.5 * navigationCamera.fov * DegRad);
this.camera.left = -frustumHalfHeight * aspect;
this.camera.right = frustumHalfHeight * aspect;
this.camera.top = frustumHalfHeight;
this.camera.bottom = -frustumHalfHeight;
- this.camera.updateProjectionMatrix ();
+ this.camera.updateProjectionMatrix();
}
}
- this.shadingModel.UpdateByCamera (navigationCamera);
- this.renderer.render (this.scene, this.camera);
+ this.shadingModel.UpdateByCamera(navigationCamera);
+ this.renderer.render(this.scene, this.camera);
}
- SetMainObject (object)
- {
- const shadingType = GetShadingTypeOfObject (object);
- this.mainModel.SetMainObject (object);
- this.shadingModel.SetShadingType (shadingType);
+ SetMainObject(object) {
+ const shadingType = GetShadingTypeOfObject(object);
+ this.mainModel.SetMainObject(object);
+ this.shadingModel.SetShadingType(shadingType);
- this.Render ();
+ this.Render();
}
- AddExtraObject (object)
- {
- this.extraModel.AddObject (object);
- this.Render ();
+ AddExtraObject(object) {
+ this.extraModel.AddObject(object);
+ this.Render();
}
- Clear ()
- {
- this.mainModel.Clear ();
- this.extraModel.Clear ();
- this.Render ();
+ Clear() {
+ this.mainModel.Clear();
+ this.extraModel.Clear();
+ this.Render();
}
- ClearExtra ()
- {
- this.extraModel.Clear ();
- this.Render ();
+ ClearExtra() {
+ this.extraModel.Clear();
+ this.Render();
}
- SetMeshesVisibility (isVisible)
- {
- this.mainModel.EnumerateMeshesAndLines ((mesh) => {
- let visible = isVisible (mesh.userData);
+ SetMeshesVisibility(isVisible) {
+ this.mainModel.EnumerateMeshesAndLines((mesh) => {
+ let visible = isVisible(mesh.userData);
if (mesh.visible !== visible) {
mesh.visible = visible;
}
});
- this.mainModel.EnumerateEdges ((edge) => {
- let visible = isVisible (edge.userData);
+ this.mainModel.EnumerateEdges((edge) => {
+ let visible = isVisible(edge.userData);
if (edge.visible !== visible) {
edge.visible = visible;
}
});
- this.Render ();
+ this.Render();
}
- SetMeshesHighlight (highlightColor, isHighlighted)
- {
- let withPolygonOffset = this.mainModel.HasLinesOrEdges ();
- this.mainModel.EnumerateMeshesAndLines ((mesh) => {
- let highlighted = isHighlighted (mesh.userData);
+ SetMeshesHighlight(highlightColor, isHighlighted) {
+ let withPolygonOffset = this.mainModel.HasLinesOrEdges();
+ this.mainModel.EnumerateMeshesAndLines((mesh) => {
+ let highlighted = isHighlighted(mesh.userData);
if (highlighted) {
if (mesh.userData.threeMaterials === null) {
mesh.userData.threeMaterials = mesh.material;
- mesh.material = CreateHighlightMaterials (mesh.userData.threeMaterials, highlightColor, withPolygonOffset);
+ mesh.material = CreateHighlightMaterials(mesh.userData.threeMaterials, highlightColor, withPolygonOffset);
}
} else {
if (mesh.userData.threeMaterials !== null) {
@@ -481,85 +438,87 @@ export class Viewer
}
});
- this.Render ();
+ this.Render();
}
- GetMeshUserDataUnderMouse (intersectionMode, mouseCoords)
- {
- let intersection = this.GetMeshIntersectionUnderMouse (intersectionMode, mouseCoords);
+ GetMeshUserDataUnderMouse(intersectionMode, mouseCoords) {
+ let intersection = this.GetMeshIntersectionUnderMouse(intersectionMode, mouseCoords);
if (intersection === null) {
return null;
}
return intersection.object.userData;
}
- GetMeshIntersectionUnderMouse (intersectionMode, mouseCoords)
- {
- let canvasSize = this.GetCanvasSize ();
- let intersection = this.mainModel.GetMeshIntersectionUnderMouse (intersectionMode, mouseCoords, this.camera, canvasSize.width, canvasSize.height);
+ GetMeshIntersectionUnderMouse(intersectionMode, mouseCoords) {
+ let canvasSize = this.GetCanvasSize();
+ let intersection = this.mainModel.GetMeshIntersectionUnderMouse(intersectionMode, mouseCoords, this.camera, canvasSize.width, canvasSize.height);
if (intersection === null) {
return null;
}
return intersection;
}
- GetBoundingBox (needToProcess)
- {
- return this.mainModel.GetBoundingBox (needToProcess);
+ GetBoundingBox(needToProcess) {
+ return this.mainModel.GetBoundingBox(needToProcess);
}
- GetBoundingSphere (needToProcess)
- {
- return this.mainModel.GetBoundingSphere (needToProcess);
+ GetBoundingSphere(needToProcess) {
+ return this.mainModel.GetBoundingSphere(needToProcess);
}
- EnumerateMeshesAndLinesUserData (enumerator)
- {
- this.mainModel.EnumerateMeshesAndLines ((mesh) => {
- enumerator (mesh.userData);
+ EnumerateMeshesAndLinesUserData(enumerator) {
+ this.mainModel.EnumerateMeshesAndLines((mesh) => {
+ enumerator(mesh.userData);
});
}
- InitNavigation ()
- {
- let camera = GetDefaultCamera (Direction.Y);
- this.camera = new THREE.PerspectiveCamera (45.0, 1.0, 0.1, 1000.0);
+ EnumerateMeshesAndLines(enumerator) {
+ this.mainModel.EnumerateMeshesAndLines((mesh) => {
+ enumerator(mesh);
+ });
+ }
+
+ EnumerateEdges(enumerator) {
+ this.mainModel.EnumerateEdges((edge) => {
+ enumerator(edge);
+ });
+ }
+
+ InitNavigation() {
+ let camera = GetDefaultCamera(Direction.Y);
+ this.camera = new THREE.PerspectiveCamera(45.0, 1.0, 0.1, 1000.0);
this.projectionMode = ProjectionMode.Perspective;
- this.cameraValidator = new CameraValidator ();
- this.scene.add (this.camera);
+ this.cameraValidator = new CameraValidator();
+ this.scene.add(this.camera);
let canvasElem = this.renderer.domElement;
- this.navigation = new Navigation (canvasElem, camera, {
- onUpdate : () => {
- this.Render ();
+ this.navigation = new Navigation(canvasElem, camera, {
+ onUpdate: () => {
+ this.Render();
}
});
- this.upVector = new UpVector ();
+ this.upVector = new UpVector();
}
- InitShading ()
- {
- this.shadingModel = new ShadingModel (this.scene);
+ InitShading() {
+ this.shadingModel = new ShadingModel(this.scene);
}
- GetShadingType ()
- {
+ GetShadingType() {
return this.shadingModel.type;
}
- GetImageSize ()
- {
- let originalSize = new THREE.Vector2 ();
- this.renderer.getSize (originalSize);
+ GetImageSize() {
+ let originalSize = new THREE.Vector2();
+ this.renderer.getSize(originalSize);
return {
- width : parseInt (originalSize.x, 10),
- height : parseInt (originalSize.y, 10)
+ width: parseInt(originalSize.x, 10),
+ height: parseInt(originalSize.y, 10)
};
}
- GetCanvasSize ()
- {
+ GetCanvasSize() {
let width = this.canvas.width;
let height = this.canvas.height;
if (window.devicePixelRatio) {
@@ -567,35 +526,33 @@ export class Viewer
height /= window.devicePixelRatio;
}
return {
- width : width,
- height : height
+ width: width,
+ height: height
};
}
- GetImageAsDataUrl (width, height, isTransparent)
- {
- let originalSize = this.GetImageSize ();
+ GetImageAsDataUrl(width, height, isTransparent) {
+ let originalSize = this.GetImageSize();
let renderWidth = width;
let renderHeight = height;
if (window.devicePixelRatio) {
renderWidth /= window.devicePixelRatio;
renderHeight /= window.devicePixelRatio;
}
- let clearAlpha = this.renderer.getClearAlpha ();
+ let clearAlpha = this.renderer.getClearAlpha();
if (isTransparent) {
- this.renderer.setClearAlpha (0.0);
+ this.renderer.setClearAlpha(0.0);
}
- this.ResizeRenderer (renderWidth, renderHeight);
- this.Render ();
- let url = this.renderer.domElement.toDataURL ();
- this.ResizeRenderer (originalSize.width, originalSize.height);
- this.renderer.setClearAlpha (clearAlpha);
+ this.ResizeRenderer(renderWidth, renderHeight);
+ this.Render();
+ let url = this.renderer.domElement.toDataURL();
+ this.ResizeRenderer(originalSize.width, originalSize.height);
+ this.renderer.setClearAlpha(clearAlpha);
return url;
}
- Destroy ()
- {
- this.Clear ();
- this.renderer.dispose ();
+ Destroy() {
+ this.Clear();
+ this.renderer.dispose();
}
}
diff --git a/source/website/css/O3DVIcons/O3DVIcons.woff b/source/website/css/O3DVIcons/O3DVIcons.woff
index 2e28dd7c..6c73da0c 100644
Binary files a/source/website/css/O3DVIcons/O3DVIcons.woff and b/source/website/css/O3DVIcons/O3DVIcons.woff differ
diff --git a/source/website/css/controls.css b/source/website/css/controls.css
index 61893ae7..df0b3255 100644
--- a/source/website/css/controls.css
+++ b/source/website/css/controls.css
@@ -1,58 +1,48 @@
-div.ov_svg_icon
-{
+div.ov_svg_icon {
color: var(--ov_icon_color);
font-size: 18px;
width: 18px;
height: 18px;
}
-div.ov_svg_icon.left
-{
+div.ov_svg_icon.left {
margin-right: 10px;
float: left;
}
-div.ov_svg_icon.left_inline
-{
+div.ov_svg_icon.left_inline {
margin-right: 10px;
margin-top: 2px;
float: left;
}
-div.ov_svg_icon.light
-{
+div.ov_svg_icon.light {
color: var(--ov_light_icon_color);
}
-div.ov_svg_icon.selected
-{
+div.ov_svg_icon.selected {
color: var(--ov_selected_icon_color);
}
-div.ov_svg_icon.disabled
-{
+div.ov_svg_icon.disabled {
color: var(--ov_disabled_icon_color);
}
-div.ov_thin_scrollbar
-{
+div.ov_thin_scrollbar {
scrollbar-color: var(--ov_border_color) transparent;
scrollbar-width: thin;
}
-div.ov_thin_scrollbar::-webkit-scrollbar
-{
+div.ov_thin_scrollbar::-webkit-scrollbar {
width: 3px;
height: 3px;
}
-div.ov_thin_scrollbar::-webkit-scrollbar-thumb
-{
+div.ov_thin_scrollbar::-webkit-scrollbar-thumb {
background: #cccccc;
}
-div.ov_button
-{
+div.ov_button {
color: var(--ov_button_text_color);
background: var(--ov_button_color);
text-align: center;
@@ -62,15 +52,13 @@ div.ov_button
cursor: pointer;
}
-div.ov_button.outline
-{
+div.ov_button.outline {
color: var(--ov_outline_button_text_color);
background: transparent;
border: 1px solid var(--ov_outline_button_color);
}
-div.ov_tooltip
-{
+div.ov_tooltip {
color: var(--ov_dialog_foreground_color);
background: var(--ov_dialog_background_color);
padding: 5px 10px;
@@ -79,25 +67,21 @@ div.ov_tooltip
box-shadow: var(--ov_shadow);
}
-input[type=text]
-{
+input[type=text] {
color: var(--ov_dialog_foreground_color);
background: var(--ov_dialog_background_color);
}
-input[type=text]:disabled
-{
+input[type=text]:disabled {
color: var(--ov_disabled_foreground_color);
}
-textarea
-{
+textarea {
color: var(--ov_dialog_foreground_color);
background: var(--ov_dialog_background_color);
}
-input.ov_radio_button
-{
+input.ov_radio_button {
position: relative;
top: 2px;
width: 14px;
@@ -111,13 +95,11 @@ input.ov_radio_button
appearance: none;
}
-input.ov_radio_button:checked
-{
+input.ov_radio_button:checked {
border: 5px solid var(--ov_button_color);
}
-input.ov_checkbox
-{
+input.ov_checkbox {
position: relative;
top: 4px;
width: 14px;
@@ -131,32 +113,28 @@ input.ov_checkbox
appearance: none;
}
-input.ov_checkbox:checked
-{
+input.ov_checkbox:checked {
background-color: var(--ov_button_color);
background-image: url('O3DVIcons/checkmark.svg');
background-position: center;
border: 0px;
}
-div.ov_select_container
-{
+div.ov_select_container {
position: relative;
}
-div.ov_select_container:after
-{
+div.ov_select_container:after {
font-family: "O3DVIcons";
font-size: 18px;
- content: "\f101";
+ content: "\f101";
position: absolute;
- right: 6px;
- top: 6px;
+ right: 6px;
+ top: 6px;
pointer-events: none;
}
-select.ov_select
-{
+select.ov_select {
color: var(--ov_dialog_foreground_color);
background: var(--ov_dialog_background_color);
font-size: 16px;
@@ -169,8 +147,7 @@ select.ov_select
appearance: none;
}
-input.ov_slider
-{
+input.ov_slider {
height: 1px;
background: var(--ov_border_color);
outline: none;
@@ -179,8 +156,7 @@ input.ov_slider
appearance: none;
}
-input.ov_slider::-webkit-slider-thumb
-{
+input.ov_slider::-webkit-slider-thumb {
background: var(--ov_button_color);
width: 14px;
height: 14px;
@@ -190,8 +166,7 @@ input.ov_slider::-webkit-slider-thumb
appearance: none;
}
-input.ov_slider::-moz-range-thumb
-{
+input.ov_slider::-moz-range-thumb {
background: var(--ov_button_color);
width: 14px;
height: 14px;
@@ -200,15 +175,13 @@ input.ov_slider::-moz-range-thumb
cursor: pointer;
}
-span.ov_slider_label
-{
+span.ov_slider_label {
margin-left: 10px;
position: relative;
bottom: -4px;
}
-div.ov_toggle
-{
+div.ov_toggle {
width: 24px;
height: 8px;
padding: 2px;
@@ -218,8 +191,7 @@ div.ov_toggle
cursor: pointer;
}
-div.ov_toggle_slider
-{
+div.ov_toggle_slider {
width: 6px;
height: 6px;
transition: .4s;
@@ -227,36 +199,30 @@ div.ov_toggle_slider
border: 1px solid var(--ov_foreground_color);
}
-div.ov_toggle.on
-{
+div.ov_toggle.on {
background: var(--ov_foreground_color);
}
-div.ov_toggle.on div.ov_toggle_slider
-{
+div.ov_toggle.on div.ov_toggle_slider {
background: var(--ov_background_color);
transform: translateX(16px);
border: 1px solid var(--ov_background_color);
}
-@media (hover)
-{
+@media (hover) {
-div.ov_svg_icon.selected:hover
-{
- color: var(--ov_hover_text_color);
-}
+ div.ov_svg_icon.selected:hover {
+ color: var(--ov_hover_text_color);
+ }
-div.ov_button:hover
-{
- background: var(--ov_button_hover_color);
- border: 1px solid var(--ov_button_hover_color);
-}
+ div.ov_button:hover {
+ background: var(--ov_button_hover_color);
+ border: 1px solid var(--ov_button_hover_color);
+ }
-div.ov_button.outline:hover
-{
- background: var(--ov_outline_button_hover_color);
- border: 1px solid var(--ov_outline_button_color);
-}
+ div.ov_button.outline:hover {
+ background: var(--ov_outline_button_hover_color);
+ border: 1px solid var(--ov_outline_button_color);
+ }
-}
+}
\ No newline at end of file
diff --git a/source/website/css/icons.css b/source/website/css/icons.css
index 589f4440..c6f07c28 100644
--- a/source/website/css/icons.css
+++ b/source/website/css/icons.css
@@ -1,6 +1,6 @@
@font-face {
font-family: "O3DVIcons";
- src: url("O3DVIcons/O3DVIcons.woff?d27bdb5af135068ed4a9350e285e132e") format("woff");
+ src: url("O3DVIcons/O3DVIcons.woff?a183607fabf1ae69b129cd0cbb17c310") format("woff");
}
i[class^="icon-"]:before, i[class*=" icon-"]:before {
@@ -56,108 +56,111 @@ i[class^="icon-"]:before, i[class*=" icon-"]:before {
.icon-expand:before {
content: "\f10e";
}
-.icon-export:before {
+.icon-explode:before {
content: "\f10f";
}
-.icon-feedback:before {
+.icon-export:before {
content: "\f110";
}
-.icon-file_download:before {
+.icon-feedback:before {
content: "\f111";
}
-.icon-files:before {
+.icon-file_download:before {
content: "\f112";
}
-.icon-fit:before {
+.icon-files:before {
content: "\f113";
}
-.icon-fix_up_off:before {
+.icon-fit:before {
content: "\f114";
}
-.icon-fix_up_on:before {
+.icon-fix_up_off:before {
content: "\f115";
}
-.icon-flat_list:before {
+.icon-fix_up_on:before {
content: "\f116";
}
-.icon-flip:before {
+.icon-flat_list:before {
content: "\f117";
}
-.icon-github:before {
+.icon-flip:before {
content: "\f118";
}
-.icon-hidden:before {
+.icon-github:before {
content: "\f119";
}
-.icon-info:before {
+.icon-hidden:before {
content: "\f11a";
}
-.icon-isolate:before {
+.icon-info:before {
content: "\f11b";
}
-.icon-light_mode:before {
+.icon-isolate:before {
content: "\f11c";
}
-.icon-materials:before {
+.icon-light_mode:before {
content: "\f11d";
}
-.icon-measure_angle:before {
+.icon-materials:before {
content: "\f11e";
}
-.icon-measure_distance_parallel:before {
+.icon-measure_angle:before {
content: "\f11f";
}
-.icon-measure_distance:before {
+.icon-measure_distance_parallel:before {
content: "\f120";
}
-.icon-measure:before {
+.icon-measure_distance:before {
content: "\f121";
}
-.icon-meshes:before {
+.icon-measure:before {
content: "\f122";
}
-.icon-missing_files:before {
+.icon-meshes:before {
content: "\f123";
}
-.icon-model:before {
+.icon-missing_files:before {
content: "\f124";
}
-.icon-open_url:before {
+.icon-model:before {
content: "\f125";
}
-.icon-open:before {
+.icon-open_url:before {
content: "\f126";
}
-.icon-print3d:before {
+.icon-open:before {
content: "\f127";
}
-.icon-settings:before {
+.icon-print3d:before {
content: "\f128";
}
-.icon-share:before {
+.icon-settings:before {
content: "\f129";
}
-.icon-snapshot:before {
+.icon-share:before {
content: "\f12a";
}
-.icon-tree_mesh:before {
+.icon-snapshot:before {
content: "\f12b";
}
-.icon-tree_view:before {
+.icon-tree_mesh:before {
content: "\f12c";
}
-.icon-twitter:before {
+.icon-tree_view:before {
content: "\f12d";
}
-.icon-up_y:before {
+.icon-twitter:before {
content: "\f12e";
}
-.icon-up_z:before {
+.icon-up_y:before {
content: "\f12f";
}
-.icon-visible:before {
+.icon-up_z:before {
content: "\f130";
}
-.icon-warning:before {
+.icon-visible:before {
content: "\f131";
}
+.icon-warning:before {
+ content: "\f132";
+}
diff --git a/source/website/css/website.css b/source/website/css/website.css
index 62c214d7..e153abaa 100644
--- a/source/website/css/website.css
+++ b/source/website/css/website.css
@@ -1,5 +1,4 @@
-div.ov_color_circle
-{
+div.ov_color_circle {
background: #ffffff;
border: 1px solid #000000;
width: 14px;
@@ -10,32 +9,27 @@ div.ov_color_circle
border-radius: 10px;
}
-div.header
-{
+div.header {
overflow: auto;
display: none;
}
-div.title
-{
+div.title {
padding: 6px 10px;
overflow: auto;
}
-div.title div.title_left
-{
+div.title div.title_left {
float: left;
}
-div.title svg.logo_image
-{
+div.title svg.logo_image {
width: 190px;
height: 40px;
float: left;
}
-div.title div.logo_text
-{
+div.title div.logo_text {
color: var(--ov_foreground_color);
font-size: 18px;
font-weight: bold;
@@ -43,13 +37,11 @@ div.title div.logo_text
float: left;
}
-div.title div.title_right
-{
+div.title div.title_right {
float: right;
}
-div.title_right a
-{
+div.title_right a {
color: var(--ov_foreground_color);
padding: 11px 5px;
display: block;
@@ -57,13 +49,11 @@ div.title_right a
text-decoration: none;
}
-div.toolbar
-{
+div.toolbar {
background: var(--ov_toolbar_background_color);
}
-div.intro
-{
+div.intro {
margin: 10px;
padding: 10px;
text-align: center;
@@ -72,47 +62,40 @@ div.intro
display: none;
}
-div.intro_content
-{
+div.intro_content {
width: 500px;
max-width: 90%;
margin: 10px auto;
position: relative;
}
-div.intro div.intro_logo
-{
+div.intro div.intro_logo {
border-bottom: 1px solid var(--ov_border_color);
padding-bottom: 30px;
margin-bottom: 30px;
}
-div.intro svg.intro_logo
-{
+div.intro svg.intro_logo {
width: 381px;
height: 80px;
max-width: 90%;
margin-bottom: 20px;
}
-div.intro div.intro_dragdrop_text
-{
+div.intro div.intro_dragdrop_text {
font-size: 30px;
}
-div.intro div.intro_formats_title
-{
+div.intro div.intro_formats_title {
font-size: 25px;
margin-bottom: 15px;
}
-div.intro div.intro_file_formats
-{
+div.intro div.intro_file_formats {
margin: 0px auto;
}
-div.intro div.intro_file_formats a
-{
+div.intro div.intro_file_formats a {
color: var(--ov_outline_button_text_color);
text-decoration: none;
font-size: 17px;
@@ -125,31 +108,26 @@ div.intro div.intro_file_formats a
cursor: pointer;
}
-div.intro div.intro_file_formats a:hover
-{
+div.intro div.intro_file_formats a:hover {
background: var(--ov_outline_button_hover_color);
}
-div.noembed
-{
+div.noembed {
text-align: center;
padding: 10px;
}
-div.noembed a
-{
+div.noembed a {
padding: 10px 0px;
display: block;
}
-div.main
-{
+div.main {
overflow: hidden;
display: none;
}
-div.main_file_name
-{
+div.main_file_name {
margin: 10px auto;
white-space: nowrap;
text-align: center;
@@ -157,80 +135,68 @@ div.main_file_name
overflow: hidden;
}
-div.main_left_container
-{
+div.main_left_container {
float: left;
overflow: auto;
}
-div.main_navigator
-{
+div.main_navigator {
width: 280px;
margin: 10px 0px 10px 0px;
overflow: none;
float: left;
}
-div.main_splitter
-{
+div.main_splitter {
width: 10px;
overflow: none;
float: left;
cursor: w-resize;
}
-div.main_viewer
-{
+div.main_viewer {
float: left;
}
-div.main_right_container
-{
+div.main_right_container {
float: left;
overflow: auto;
}
-div.main_sidebar
-{
+div.main_sidebar {
width: 280px;
margin: 10px 0px 10px 0px;
overflow: none;
float: left;
}
-div.main_viewer canvas
-{
+div.main_viewer canvas {
margin: 10px 0px 10px 0px;
border: 1px solid var(--ov_border_color);
outline: none;
display: block;
}
-div.ov_toolbar
-{
+div.ov_toolbar {
overflow: auto;
user-select: none;
}
-div.ov_toolbar div.ov_toolbar_button
-{
+div.ov_toolbar div.ov_toolbar_button {
float: left;
cursor: pointer;
padding: 10px;
}
-div.ov_toolbar div.ov_toolbar_button.align_right
-{
+div.ov_toolbar div.ov_toolbar_button.align_right {
float: right;
}
-div.ov_toolbar div.ov_toolbar_button.selected
-{
+div.ov_toolbar div.ov_toolbar_button.selected {
background: var(--ov_toolbar_selected_color);
}
-div.ov_toolbar div.ov_toolbar_separator
-{
+div.ov_toolbar div.ov_toolbar_separator {
background: var(--ov_toolbar_separator_color);
width: 1px;
height: 28px;
@@ -238,50 +204,42 @@ div.ov_toolbar div.ov_toolbar_separator
float: left;
}
-div.pcr-app
-{
+div.pcr-app {
color: var(--ov_dialog_foreground_color);
background: var(--ov_dialog_background_color);
}
-div.pcr-app input.pcr-result
-{
+div.pcr-app input.pcr-result {
color: var(--ov_foreground_color) !important;
background: var(--ov_background_color) !important;
}
-div.ov_property_table
-{
+div.ov_property_table {
overflow: auto;
}
-div.ov_property_table_custom
-{
+div.ov_property_table_custom {
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid var(--ov_border_color);
}
-div.ov_property_table div.ov_property_table_row
-{
+div.ov_property_table div.ov_property_table_row {
overflow: auto;
}
-div.ov_property_table div.ov_property_table_row.group
-{
+div.ov_property_table div.ov_property_table_row.group {
padding: 4px 0px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
-div.ov_property_table div.ov_property_table_row.ingroup
-{
+div.ov_property_table div.ov_property_table_row.ingroup {
margin-left: 15px;
}
-div.ov_property_table div.ov_property_table_cell
-{
+div.ov_property_table div.ov_property_table_cell {
padding: 4px 0px;
white-space: nowrap;
text-overflow: ellipsis;
@@ -289,28 +247,24 @@ div.ov_property_table div.ov_property_table_cell
box-sizing: border-box;
}
-div.ov_property_table div.ov_property_table_name
-{
+div.ov_property_table div.ov_property_table_name {
width: 49%;
padding-right: 2%;
float: left;
}
-div.ov_property_table div.ov_property_table_value
-{
+div.ov_property_table div.ov_property_table_value {
width: 49%;
text-align: left;
float: left;
}
-div.ov_property_table div.ov_property_table_button
-{
+div.ov_property_table div.ov_property_table_button {
color: var(--ov_button_color);
cursor: pointer;
}
-div.ov_bottom_floating_panel
-{
+div.ov_bottom_floating_panel {
background: var(--ov_background_color);
border-top: 1px solid var(--ov_border_color);
width: 100%;
@@ -320,97 +274,103 @@ div.ov_bottom_floating_panel
bottom: 0px;
}
-div.ov_bottom_floating_panel div.ov_floating_panel_text
-{
+div.ov_bottom_floating_panel div.ov_floating_panel_text {
padding: 3px;
margin-bottom: 10px;
float: left;
}
-div.ov_bottom_floating_panel div.ov_floating_panel_button
-{
+div.ov_bottom_floating_panel div.ov_floating_panel_button {
width: 120px;
float: right;
}
-div.ov_measure_panel
-{
+div.ov_measure_panel {
padding: 6px 15px;
position: absolute;
border-radius: 30px;
- left : 0px;
- top : 0px;
+ left: 0px;
+ top: 0px;
}
-div.ov_measure_panel div.ov_svg_icon
-{
+div.ov_measure_panel div.ov_svg_icon {
color: inherit;
margin-bottom: 2px;
}
-div.ov_measure_panel div.ov_measure_value
-{
+div.ov_measure_panel div.ov_measure_value {
float: left;
margin-right: 10px;
}
-@media (hover)
-{
-
-div.title_right div.header_button:hover
-{
- color: var(--ov_button_color);
+div.ov_explode_panel {
+ padding: 15px 20px;
+ position: absolute;
+ border-radius: 10px;
+ background: var(--ov_background_color);
+ border: 1px solid var(--ov_border_color);
+ left: 0px;
+ bottom: 0px;
+ min-width: 300px;
+ z-index: 100;
}
-div.ov_toolbar div.ov_toolbar_button:hover
-{
- background: var(--ov_hover_color);
+div.ov_explode_slider {
+ width: 250px;
+ margin: 0px 10px;
}
+div.ov_toolbar_button.ov_hidden,
+div.ov_toolbar_separator.ov_hidden {
+ display: none;
}
-@media (max-width: 350px), (max-height: 620px)
-{
+@media (hover) {
-div.intro_content
-{
- margin: 0px auto;
-}
+ div.title_right div.header_button:hover {
+ color: var(--ov_button_color);
+ }
-div.intro div.intro_logo
-{
- display: none;
-}
+ div.ov_toolbar div.ov_toolbar_button:hover {
+ background: var(--ov_hover_color);
+ }
}
-@media (max-width: 800px)
-{
+@media (max-width: 350px),
+(max-height: 620px) {
-div.intro_content
-{
- width: auto;
-}
+ div.intro_content {
+ margin: 0px auto;
+ }
-div.main_viewer canvas
-{
- border: 0px;
- margin: 0px;
-}
+ div.intro div.intro_logo {
+ display: none;
+ }
-div.ov_dialog
-{
- max-width: 80%;
}
-div.ov_progress
-{
- max-width: 80%;
-}
+@media (max-width: 800px) {
-div.ov_bottom_floating_panel
-{
- padding: 10px;
-}
+ div.intro_content {
+ width: auto;
+ }
-}
+ div.main_viewer canvas {
+ border: 0px;
+ margin: 0px;
+ }
+
+ div.ov_dialog {
+ max-width: 80%;
+ }
+
+ div.ov_progress {
+ max-width: 80%;
+ }
+
+ div.ov_bottom_floating_panel {
+ padding: 10px;
+ }
+
+}
\ No newline at end of file
diff --git a/source/website/explodetool.js b/source/website/explodetool.js
new file mode 100644
index 00000000..4a5fc121
--- /dev/null
+++ b/source/website/explodetool.js
@@ -0,0 +1,445 @@
+import { AddDiv, AddDomElement } from '../engine/viewer/domutils.js';
+import { Loc } from '../engine/core/localization.js';
+import * as THREE from 'three';
+
+export class ExplodeTool {
+ constructor(viewer, settings) {
+ this.viewer = viewer;
+ this.settings = settings;
+ this.isActive = false;
+ this.explodeValue = 0.0;
+ this.originalPositions = new Map();
+ this.originalEdgePositions = new Map();
+ this.meshToEdgeMap = new Map(); // Maps mesh uuid to edge uuid
+ this.modelCenter = new THREE.Vector3();
+ this.boundingSphereRadius = 0.0;
+
+ this.panel = null;
+ this.slider = null;
+ this.button = null;
+ this.separator = null;
+ }
+
+ SetButton(button) {
+ this.button = button;
+ }
+
+ SetSeparator(separator) {
+ this.separator = separator;
+ }
+
+ IsActive() {
+ return this.isActive;
+ }
+
+ SetActive(isActive) {
+ if (this.isActive === isActive) {
+ return;
+ }
+ this.isActive = isActive;
+ this.button.SetSelected(isActive);
+ if (this.isActive) {
+ let meshCount = this.InitializeExplode();
+ if (meshCount <= 1) {
+ // Not enough meshes to explode, deactivate
+ this.isActive = false;
+ this.button.SetSelected(false);
+ return;
+ }
+ this.CreatePanel();
+ this.Resize();
+ } else {
+ this.ResetExplode();
+ this.panel.remove();
+ this.panel = null;
+ this.slider = null;
+ }
+ }
+
+ GetMeshCount() {
+ let meshCount = 0;
+ this.viewer.EnumerateMeshesAndLines((obj) => {
+ obj.traverse((child) => {
+ if (child.isMesh) {
+ meshCount++;
+ }
+ });
+ });
+ return meshCount;
+ }
+
+ UpdateButtonVisibility() {
+ let meshCount = this.GetMeshCount();
+ if (meshCount <= 1) {
+ this.button.AddClass('ov_hidden');
+ if (this.separator) {
+ this.separator.classList.add('ov_hidden');
+ }
+ } else {
+ this.button.RemoveClass('ov_hidden');
+ if (this.separator) {
+ this.separator.classList.remove('ov_hidden');
+ }
+ }
+ }
+
+ InitializeExplode() {
+ // Calculate the center of the model
+ let boundingSphere = this.viewer.GetBoundingSphere((meshUserData) => {
+ return true;
+ });
+
+ this.modelCenter.copy(boundingSphere.center);
+ this.boundingSphereRadius = boundingSphere.radius;
+
+ // Store original positions and mesh centers for ALL meshes (including nested ones)
+ this.originalPositions.clear();
+ this.originalEdgePositions.clear();
+ this.meshToEdgeMap.clear();
+ let meshCount = 0;
+
+ // Get the scene's root object and traverse EVERYTHING
+ this.viewer.EnumerateMeshesAndLines((obj) => {
+ // Traverse this object and all its children
+ obj.traverse((child) => {
+ if (child.isMesh) {
+ meshCount++;
+
+ // Update world matrices first!
+ child.updateMatrixWorld(true);
+
+ // Store original LOCAL position
+ let originalLocalPos = new THREE.Vector3();
+ originalLocalPos.copy(child.position);
+
+ // Get the mesh's world position
+ let worldPos = new THREE.Vector3();
+ child.getWorldPosition(worldPos);
+
+ // Calculate the mesh's geometric center (in world space)
+ if (!child.geometry.boundingBox) {
+ child.geometry.computeBoundingBox();
+ }
+ let boundingBox = child.geometry.boundingBox;
+ let meshCenter = new THREE.Vector3();
+ boundingBox.getCenter(meshCenter);
+
+ // Transform to world space
+ let worldCenter = meshCenter.clone();
+ child.localToWorld(worldCenter);
+
+ // Calculate direction from model center to mesh center
+ let direction = new THREE.Vector3();
+ direction.subVectors(worldCenter, this.modelCenter);
+
+ // If the mesh is at the center, generate a random direction NOW (not later)
+ if (direction.length() < 0.001) {
+ direction.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5);
+ direction.normalize();
+ } else {
+ direction.normalize();
+ }
+
+ this.originalPositions.set(child.uuid, {
+ localPosition: originalLocalPos,
+ worldPosition: worldPos,
+ center: worldCenter,
+ direction: direction,
+ parent: child.parent,
+ userData: child.userData
+ });
+ }
+ });
+ });
+
+ // Store original edge positions and map them to their meshes
+ this.viewer.EnumerateEdges((edge) => {
+ edge.updateMatrixWorld(true);
+
+ // Store original position
+ let originalLocalPos = new THREE.Vector3();
+ originalLocalPos.copy(edge.position);
+
+ // Get world position
+ let worldPos = new THREE.Vector3();
+ edge.getWorldPosition(worldPos);
+
+ this.originalEdgePositions.set(edge.uuid, {
+ localPosition: originalLocalPos,
+ worldPosition: worldPos,
+ parent: edge.parent,
+ userData: edge.userData
+ });
+
+ // Find the corresponding mesh using userData
+ // Edge userData should match mesh userData
+ for (let [meshUuid, meshData] of this.originalPositions.entries()) {
+ if (meshData.userData === edge.userData) {
+ this.meshToEdgeMap.set(meshUuid, edge.uuid);
+ break;
+ }
+ }
+ });
+
+ return meshCount;
+ }
+
+ SetExplodeValue(value) {
+ this.explodeValue = value;
+ this.ApplyExplode();
+ this.viewer.Render();
+ }
+
+ RefreshEdges() {
+ // This method should be called when edges are toggled on during explode
+ // It will initialize the edge positions and apply the current explode state
+ if (!this.isActive) {
+ return;
+ }
+
+ // Clear existing edge data
+ this.originalEdgePositions.clear();
+ this.meshToEdgeMap.clear();
+
+ // Store original edge positions and map them to their meshes
+ this.viewer.EnumerateEdges((edge) => {
+ edge.updateMatrixWorld(true);
+
+ // Store original position (in current exploded state)
+ let originalLocalPos = new THREE.Vector3();
+ originalLocalPos.copy(edge.position);
+
+ // Get world position
+ let worldPos = new THREE.Vector3();
+ edge.getWorldPosition(worldPos);
+
+ // We need to "unexplode" the world position to get the true original
+ // Find the corresponding mesh
+ let correspondingMeshData = null;
+ for (let [meshUuid, meshData] of this.originalPositions.entries()) {
+ if (meshData.userData === edge.userData) {
+ correspondingMeshData = meshData;
+ this.meshToEdgeMap.set(meshUuid, edge.uuid);
+ break;
+ }
+ }
+
+ // If we found the mesh, calculate the original edge position
+ if (correspondingMeshData) {
+ // The edge was just generated at the mesh's current (exploded) position
+ // We need to store what the original position would have been
+ let maxDistance = this.boundingSphereRadius * 2.0;
+ let direction = correspondingMeshData.direction.clone();
+ let offset = direction.multiplyScalar(maxDistance * this.explodeValue);
+
+ // The current world position includes the explode offset
+ // So the original world position is current minus offset
+ let originalWorldPos = new THREE.Vector3();
+ originalWorldPos.subVectors(worldPos, offset);
+
+ this.originalEdgePositions.set(edge.uuid, {
+ localPosition: originalLocalPos,
+ worldPosition: originalWorldPos,
+ parent: edge.parent,
+ userData: edge.userData
+ });
+
+ // Now apply the explode to this edge (it will be applied in ApplyExplode)
+ } else {
+ // No corresponding mesh found, just store current position
+ this.originalEdgePositions.set(edge.uuid, {
+ localPosition: originalLocalPos,
+ worldPosition: worldPos,
+ parent: edge.parent,
+ userData: edge.userData
+ });
+ }
+ });
+
+ // Apply current explode state to the new edges
+ if (this.explodeValue > 0) {
+ this.ApplyExplode();
+ }
+ }
+
+ ApplyExplode() {
+ let maxDistance = this.boundingSphereRadius * 2.0;
+
+ // Traverse ALL objects including nested children
+ this.viewer.EnumerateMeshesAndLines((obj) => {
+ obj.traverse((child) => {
+ if (child.isMesh) {
+ let meshData = this.originalPositions.get(child.uuid);
+ if (meshData) {
+ // Use the pre-calculated direction (already normalized)
+ let direction = meshData.direction.clone();
+
+ // Apply explode offset in world space
+ let offset = direction.multiplyScalar(maxDistance * this.explodeValue);
+ let newWorldPos = new THREE.Vector3();
+ newWorldPos.addVectors(meshData.worldPosition, offset);
+
+ // Convert world position back to local position
+ if (child.parent) {
+ let parentWorldMatrix = new THREE.Matrix4();
+ child.parent.matrixWorld.decompose(
+ new THREE.Vector3(),
+ new THREE.Quaternion(),
+ new THREE.Vector3()
+ );
+
+ // Transform world position to parent's local space
+ let parentInverse = new THREE.Matrix4();
+ parentInverse.copy(child.parent.matrixWorld).invert();
+ let newLocalPos = newWorldPos.clone();
+ newLocalPos.applyMatrix4(parentInverse);
+
+ child.position.copy(newLocalPos);
+ } else {
+ // No parent, world = local
+ child.position.copy(newWorldPos);
+ }
+
+ child.updateMatrix();
+ }
+ }
+ });
+ });
+
+ // Apply the same transformation to edges
+ this.viewer.EnumerateEdges((edge) => {
+ let edgeData = this.originalEdgePositions.get(edge.uuid);
+ if (edgeData) {
+ // Find the corresponding mesh for this edge
+ let correspondingMeshUuid = null;
+ for (let [meshUuid, edgeUuid] of this.meshToEdgeMap.entries()) {
+ if (edgeUuid === edge.uuid) {
+ correspondingMeshUuid = meshUuid;
+ break;
+ }
+ }
+
+ if (correspondingMeshUuid) {
+ let meshData = this.originalPositions.get(correspondingMeshUuid);
+ if (meshData) {
+ // Use the same direction and offset as the mesh
+ let direction = meshData.direction.clone();
+ let offset = direction.multiplyScalar(maxDistance * this.explodeValue);
+ let newWorldPos = new THREE.Vector3();
+ newWorldPos.addVectors(edgeData.worldPosition, offset);
+
+ // Convert world position back to local position
+ if (edge.parent) {
+ let parentInverse = new THREE.Matrix4();
+ parentInverse.copy(edge.parent.matrixWorld).invert();
+ let newLocalPos = newWorldPos.clone();
+ newLocalPos.applyMatrix4(parentInverse);
+
+ edge.position.copy(newLocalPos);
+ } else {
+ // No parent, world = local
+ edge.position.copy(newWorldPos);
+ }
+
+ edge.updateMatrix();
+ }
+ }
+ }
+ });
+ }
+
+ ResetExplode() {
+ // Reset all meshes to their original positions
+ this.viewer.EnumerateMeshesAndLines((obj) => {
+ obj.traverse((child) => {
+ if (child.isMesh) {
+ let meshData = this.originalPositions.get(child.uuid);
+ if (meshData) {
+ child.position.copy(meshData.localPosition);
+ child.updateMatrix();
+ }
+ }
+ });
+ });
+
+ // Reset all edges to their original positions
+ this.viewer.EnumerateEdges((edge) => {
+ let edgeData = this.originalEdgePositions.get(edge.uuid);
+ if (edgeData) {
+ edge.position.copy(edgeData.localPosition);
+ edge.updateMatrix();
+ }
+ });
+
+ this.originalPositions.clear();
+ this.originalEdgePositions.clear();
+ this.meshToEdgeMap.clear();
+ this.explodeValue = 0.0;
+ this.viewer.Render();
+ }
+
+ CreatePanel() {
+ this.panel = AddDiv(document.body, 'ov_explode_panel');
+
+ // Add label
+ let label = AddDiv(this.panel, null);
+ label.innerHTML = Loc('Explode View');
+ label.style.display = 'inline-block';
+ label.style.marginRight = '10px';
+ label.style.fontWeight = 'bold';
+
+ // Add slider
+ this.slider = AddDomElement(this.panel, 'input', 'ov_explode_slider');
+ this.slider.setAttribute('type', 'range');
+ this.slider.setAttribute('min', '0');
+ this.slider.setAttribute('max', '100');
+ this.slider.setAttribute('value', '0');
+ this.slider.style.verticalAlign = 'middle';
+
+ // Add value display
+ let valueDisplay = AddDiv(this.panel, null);
+ valueDisplay.innerHTML = '0%';
+ valueDisplay.style.display = 'inline-block';
+ valueDisplay.style.marginLeft = '10px';
+ valueDisplay.style.minWidth = '40px';
+
+ this.slider.addEventListener('input', (ev) => {
+ let value = parseInt(ev.target.value, 10) / 100.0;
+ this.SetExplodeValue(value);
+ valueDisplay.innerHTML = parseInt(ev.target.value, 10) + '%';
+ });
+
+ this.UpdatePanelStyle();
+ }
+
+ UpdatePanelStyle() {
+ if (!this.panel) {
+ return;
+ }
+
+ if (this.settings.backgroundIsEnvMap) {
+ this.panel.style.color = '#ffffff';
+ this.panel.style.backgroundColor = 'rgba(0,0,0,0.7)';
+ } else {
+ this.panel.style.color = 'var(--ov_foreground_color)';
+ this.panel.style.backgroundColor = 'var(--ov_background_color)';
+ }
+ }
+
+ Resize() {
+ if (!this.isActive || !this.panel) {
+ return;
+ }
+
+ let canvas = this.viewer.GetCanvas();
+ let canvasRect = canvas.getBoundingClientRect();
+ let panelRect = this.panel.getBoundingClientRect();
+ let canvasWidth = canvasRect.right - canvasRect.left;
+ let panelWidth = panelRect.right - panelRect.left;
+
+ // Center horizontally at the bottom of the canvas
+ this.panel.style.left = (canvasRect.left + (canvasWidth - panelWidth) / 2) + 'px';
+ this.panel.style.bottom = '20px';
+ }
+}
+
diff --git a/source/website/index.js b/source/website/index.js
index 8b089746..4b108763 100644
--- a/source/website/index.js
+++ b/source/website/index.js
@@ -9,6 +9,7 @@ import { ShowMessageDialog } from './dialogs.js';
import * as Engine from '../engine/main.js';
export { Engine };
+export { Website };
import './css/icons.css';
import './css/themes.css';
@@ -30,63 +31,59 @@ export const UI = {
Loc
};
-export function SetWebsiteEventHandler (eventHandler)
-{
- SetEventHandler (eventHandler);
+export function SetWebsiteEventHandler(eventHandler) {
+ SetEventHandler(eventHandler);
}
-export function RegisterHeaderPlugin (plugin)
-{
- RegisterPlugin (PluginType.Header, plugin);
+export function RegisterHeaderPlugin(plugin) {
+ RegisterPlugin(PluginType.Header, plugin);
}
-export function RegisterToolbarPlugin (plugin)
-{
- RegisterPlugin (PluginType.Toolbar, plugin);
+export function RegisterToolbarPlugin(plugin) {
+ RegisterPlugin(PluginType.Toolbar, plugin);
}
-export function StartWebsite ()
-{
- window.addEventListener ('load', () => {
+export function StartWebsite() {
+ window.addEventListener('load', () => {
if (window.self !== window.top) {
- let noEmbeddingDiv = AddDiv (document.body, 'noembed');
- AddDiv (noEmbeddingDiv, null, Loc ('Embedding Online 3D Viewer in an iframe is not supported.'));
- let link = AddDomElement (noEmbeddingDiv, 'a', null, Loc ('Open Online 3D Viewer'));
+ let noEmbeddingDiv = AddDiv(document.body, 'noembed');
+ AddDiv(noEmbeddingDiv, null, Loc('Embedding Online 3D Viewer in an iframe is not supported.'));
+ let link = AddDomElement(noEmbeddingDiv, 'a', null, Loc('Open Online 3D Viewer'));
link.target = '_blank';
link.href = window.self.location;
return;
}
- document.getElementById ('intro_dragdrop_text').innerHTML = Loc ('Drag and drop 3D models here.');
- document.getElementById ('intro_formats_title').innerHTML = Loc ('Check an example file:');
+ document.getElementById('intro_dragdrop_text').innerHTML = Loc('Drag and drop 3D models here.');
+ document.getElementById('intro_formats_title').innerHTML = Loc('Check an example file:');
- let website = new Website ({
- headerDiv : document.getElementById ('header'),
- headerButtonsDiv : document.getElementById ('header_buttons'),
- toolbarDiv : document.getElementById ('toolbar'),
- mainDiv : document.getElementById ('main'),
- introDiv : document.getElementById ('intro'),
- fileNameDiv : document.getElementById ('main_file_name'),
- leftContainerDiv : document.getElementById ('main_left_container'),
- navigatorDiv : document.getElementById ('main_navigator'),
- navigatorSplitterDiv : document.getElementById ('main_navigator_splitter'),
- rightContainerDiv : document.getElementById ('main_right_container'),
- sidebarDiv : document.getElementById ('main_sidebar'),
- sidebarSplitterDiv : document.getElementById ('main_sidebar_splitter'),
- viewerDiv : document.getElementById ('main_viewer'),
- fileInput : document.getElementById ('open_file')
+ let website = new Website({
+ headerDiv: document.getElementById('header'),
+ headerButtonsDiv: document.getElementById('header_buttons'),
+ toolbarDiv: document.getElementById('toolbar'),
+ mainDiv: document.getElementById('main'),
+ introDiv: document.getElementById('intro'),
+ introContentDiv: document.getElementById('intro_content'),
+ fileNameDiv: document.getElementById('main_file_name'),
+ leftContainerDiv: document.getElementById('main_left_container'),
+ navigatorDiv: document.getElementById('main_navigator'),
+ navigatorSplitterDiv: document.getElementById('main_navigator_splitter'),
+ rightContainerDiv: document.getElementById('main_right_container'),
+ sidebarDiv: document.getElementById('main_sidebar'),
+ sidebarSplitterDiv: document.getElementById('main_sidebar_splitter'),
+ viewerDiv: document.getElementById('main_viewer'),
+ fileInput: document.getElementById('open_file')
});
- website.Load ();
+ website.Load();
});
}
-export function StartEmbed ()
-{
- window.addEventListener ('load', () => {
- let embed = new Embed ({
- viewerDiv : document.getElementById ('embed_viewer'),
- websiteLinkDiv : document.getElementById ('website_link')
+export function StartEmbed() {
+ window.addEventListener('load', () => {
+ let embed = new Embed({
+ viewerDiv: document.getElementById('embed_viewer'),
+ websiteLinkDiv: document.getElementById('website_link')
});
- embed.Load ();
+ embed.Load();
});
}
diff --git a/source/website/website.js b/source/website/website.js
index 682cc26b..1dbde994 100644
--- a/source/website/website.js
+++ b/source/website/website.js
@@ -23,6 +23,7 @@ import { GetDefaultMaterials, ReplaceDefaultMaterialsColor } from '../engine/mod
import { Direction } from '../engine/geometry/geometry.js';
import { CookieGetBoolVal, CookieSetBoolVal } from './cookiehandler.js';
import { MeasureTool } from './measuretool.js';
+import { ExplodeTool } from './explodetool.js';
import { CloseAllDialogs } from './dialog.js';
import { CreateVerticalSplitter } from './splitter.js';
import { EnumeratePlugins, PluginType } from './pluginregistry.js';
@@ -32,71 +33,67 @@ import { Loc } from '../engine/core/localization.js';
const WebsiteUIState =
{
- Undefined : 0,
- Intro : 1,
- Model : 2,
- Loading : 3
+ Undefined: 0,
+ Intro: 1,
+ Model: 2,
+ Loading: 3
};
-class WebsiteLayouter
-{
- constructor (parameters, navigator, sidebar, viewer, measureTool)
- {
+class WebsiteLayouter {
+ constructor(parameters, navigator, sidebar, viewer, measureTool, explodeTool) {
this.parameters = parameters;
this.navigator = navigator;
this.sidebar = sidebar;
this.viewer = viewer;
this.measureTool = measureTool;
+ this.explodeTool = explodeTool;
this.limits = {
- minPanelWidth : 290,
- minCanvasWidth : 100
+ minPanelWidth: 290,
+ minCanvasWidth: 100
};
}
- Init ()
- {
- this.InstallSplitter (this.parameters.navigatorSplitterDiv, this.parameters.navigatorDiv, (originalWidth, xDiff) => {
+ Init() {
+ this.InstallSplitter(this.parameters.navigatorSplitterDiv, this.parameters.navigatorDiv, (originalWidth, xDiff) => {
let newWidth = originalWidth + xDiff;
- this.OnSplitterDragged (newWidth - this.navigator.GetWidth (), 0);
+ this.OnSplitterDragged(newWidth - this.navigator.GetWidth(), 0);
});
- this.InstallSplitter (this.parameters.sidebarSplitterDiv, this.parameters.sidebarDiv, (originalWidth, xDiff) => {
+ this.InstallSplitter(this.parameters.sidebarSplitterDiv, this.parameters.sidebarDiv, (originalWidth, xDiff) => {
let newWidth = originalWidth - xDiff;
- this.OnSplitterDragged (0, newWidth - this.sidebar.GetWidth ());
+ this.OnSplitterDragged(0, newWidth - this.sidebar.GetWidth());
});
- this.Resize ();
+ this.Resize();
}
- InstallSplitter (splitterDiv, resizedDiv, onSplit)
- {
+ InstallSplitter(splitterDiv, resizedDiv, onSplit) {
let originalWidth = null;
- CreateVerticalSplitter (splitterDiv, {
- onSplitStart : () => {
- originalWidth = GetDomElementOuterWidth (resizedDiv);
+ CreateVerticalSplitter(splitterDiv, {
+ onSplitStart: () => {
+ originalWidth = GetDomElementOuterWidth(resizedDiv);
},
- onSplit : (xDiff) => {
- onSplit (originalWidth, xDiff);
+ onSplit: (xDiff) => {
+ onSplit(originalWidth, xDiff);
}
});
}
- OnSplitterDragged (leftDiff, rightDiff)
- {
+ OnSplitterDragged(leftDiff, rightDiff) {
let windowWidth = window.innerWidth;
- let navigatorWidth = this.navigator.GetWidth ();
- let sidebarWidth = this.sidebar.GetWidth ();
+ let navigatorWidth = this.navigator.GetWidth();
+ let sidebarWidth = this.sidebar.GetWidth();
- let leftWidth = GetDomElementOuterWidth (this.parameters.leftContainerDiv);
- let rightWidth = GetDomElementOuterWidth (this.parameters.rightContainerDiv);
+ let leftWidth = GetDomElementOuterWidth(this.parameters.leftContainerDiv);
+ let rightWidth = GetDomElementOuterWidth(this.parameters.rightContainerDiv);
let newLeftWidth = leftWidth + leftDiff;
let newRightWidth = rightWidth + rightDiff;
let contentNewWidth = windowWidth - newLeftWidth - newRightWidth;
- let isNavigatorVisible = this.navigator.IsPanelsVisible ();
- let isSidebarVisible = this.sidebar.IsPanelsVisible ();
+ let isNavigatorVisible = this.navigator.IsPanelsVisible();
+ let isSidebarVisible = this.sidebar.IsPanelsVisible();
if (isNavigatorVisible && newLeftWidth < this.limits.minPanelWidth) {
newLeftWidth = this.limits.minPanelWidth;
@@ -116,18 +113,17 @@ class WebsiteLayouter
if (isNavigatorVisible) {
let newNavigatorWidth = navigatorWidth + (newLeftWidth - leftWidth);
- this.navigator.SetWidth (newNavigatorWidth);
+ this.navigator.SetWidth(newNavigatorWidth);
}
if (isSidebarVisible) {
let newSidebarWidth = sidebarWidth + (newRightWidth - rightWidth);
- this.sidebar.SetWidth (newSidebarWidth);
+ this.sidebar.SetWidth(newSidebarWidth);
}
- this.Resize ();
+ this.Resize();
}
- Resize ()
- {
+ Resize() {
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
let headerHeight = this.parameters.headerDiv.offsetHeight;
@@ -135,9 +131,9 @@ class WebsiteLayouter
let leftWidth = 0;
let rightWidth = 0;
let safetyMargin = 0;
- if (!IsSmallWidth ()) {
- leftWidth = GetDomElementOuterWidth (this.parameters.leftContainerDiv);
- rightWidth = GetDomElementOuterWidth (this.parameters.rightContainerDiv);
+ if (!IsSmallWidth()) {
+ leftWidth = GetDomElementOuterWidth(this.parameters.leftContainerDiv);
+ rightWidth = GetDomElementOuterWidth(this.parameters.rightContainerDiv);
safetyMargin = 1;
}
@@ -147,108 +143,108 @@ class WebsiteLayouter
if (contentWidth < this.limits.minCanvasWidth) {
let neededIncrease = this.limits.minCanvasWidth - contentWidth;
- let isNavigatorVisible = this.navigator.IsPanelsVisible ();
- let isSidebarVisible = this.sidebar.IsPanelsVisible ();
+ let isNavigatorVisible = this.navigator.IsPanelsVisible();
+ let isSidebarVisible = this.sidebar.IsPanelsVisible();
if (neededIncrease > 0 && isNavigatorVisible) {
- let navigatorDecrease = Math.min (neededIncrease, leftWidth - this.limits.minPanelWidth);
- this.navigator.SetWidth (this.navigator.GetWidth () - navigatorDecrease);
+ let navigatorDecrease = Math.min(neededIncrease, leftWidth - this.limits.minPanelWidth);
+ this.navigator.SetWidth(this.navigator.GetWidth() - navigatorDecrease);
neededIncrease = neededIncrease - navigatorDecrease;
}
if (neededIncrease > 0 && isSidebarVisible) {
- let sidebarDecrease = Math.min (neededIncrease, rightWidth - this.limits.minPanelWidth);
- this.sidebar.SetWidth (this.sidebar.GetWidth () - sidebarDecrease);
+ let sidebarDecrease = Math.min(neededIncrease, rightWidth - this.limits.minPanelWidth);
+ this.sidebar.SetWidth(this.sidebar.GetWidth() - sidebarDecrease);
}
- leftWidth = GetDomElementOuterWidth (this.parameters.leftContainerDiv);
- rightWidth = GetDomElementOuterWidth (this.parameters.rightContainerDiv);
+ leftWidth = GetDomElementOuterWidth(this.parameters.leftContainerDiv);
+ rightWidth = GetDomElementOuterWidth(this.parameters.rightContainerDiv);
contentWidth = windowWidth - leftWidth - rightWidth;
}
- this.navigator.Resize (contentHeight);
- SetDomElementOuterHeight (this.parameters.navigatorSplitterDiv, contentHeight);
+ this.navigator.Resize(contentHeight);
+ SetDomElementOuterHeight(this.parameters.navigatorSplitterDiv, contentHeight);
+
+ this.sidebar.Resize(contentHeight);
+ SetDomElementOuterHeight(this.parameters.sidebarSplitterDiv, contentHeight);
- this.sidebar.Resize (contentHeight);
- SetDomElementOuterHeight (this.parameters.sidebarSplitterDiv, contentHeight);
+ SetDomElementOuterHeight(this.parameters.introDiv, contentHeight);
+ this.viewer.Resize(contentWidth - safetyMargin, contentHeight);
- SetDomElementOuterHeight (this.parameters.introDiv, contentHeight);
- this.viewer.Resize (contentWidth - safetyMargin, contentHeight);
+ let introContentHeight = GetDomElementOuterHeight(this.parameters.introContentDiv);
+ let introContentTop = (contentHeight - introContentHeight) / 3.0;
+ this.parameters.introContentDiv.style.top = introContentTop.toString() + 'px';
- this.measureTool.Resize ();
+ this.measureTool.Resize();
+ this.explodeTool.Resize();
}
}
-export class Website
-{
- constructor (parameters)
- {
+export class Website {
+ constructor(parameters) {
this.parameters = parameters;
- this.settings = new Settings (Theme.Light);
- this.cameraSettings = new CameraSettings ();
- this.viewer = new Viewer ();
- this.measureTool = new MeasureTool (this.viewer, this.settings);
- this.hashHandler = new HashHandler ();
- this.toolbar = new Toolbar (this.parameters.toolbarDiv);
- this.navigator = new Navigator (this.parameters.navigatorDiv);
- this.sidebar = new Sidebar (this.parameters.sidebarDiv, this.settings);
- this.modelLoaderUI = new ThreeModelLoaderUI ();
- this.themeHandler = new ThemeHandler ();
- this.highlightColor = new RGBColor (142, 201, 240);
+ this.settings = new Settings(Theme.Light);
+ this.cameraSettings = new CameraSettings();
+ this.viewer = new Viewer();
+ this.measureTool = new MeasureTool(this.viewer, this.settings);
+ this.explodeTool = new ExplodeTool(this.viewer, this.settings);
+ this.hashHandler = new HashHandler();
+ this.toolbar = new Toolbar(this.parameters.toolbarDiv);
+ this.navigator = new Navigator(this.parameters.navigatorDiv);
+ this.sidebar = new Sidebar(this.parameters.sidebarDiv, this.settings);
+ this.modelLoaderUI = new ThreeModelLoaderUI();
+ this.themeHandler = new ThemeHandler();
+ this.highlightColor = new RGBColor(142, 201, 240);
this.uiState = WebsiteUIState.Undefined;
- this.layouter = new WebsiteLayouter (this.parameters, this.navigator, this.sidebar, this.viewer, this.measureTool);
+ this.layouter = new WebsiteLayouter(this.parameters, this.navigator, this.sidebar, this.viewer, this.measureTool, this.explodeTool);
this.model = null;
}
- Load ()
- {
- this.settings.LoadFromCookies ();
- this.cameraSettings.LoadFromCookies ();
+ Load() {
+ this.settings.LoadFromCookies();
+ this.cameraSettings.LoadFromCookies();
- this.SwitchTheme (this.settings.themeId, false);
- HandleEvent ('theme_on_load', this.settings.themeId === Theme.Light ? 'light' : 'dark');
+ this.SwitchTheme(this.settings.themeId, false);
+ HandleEvent('theme_on_load', this.settings.themeId === Theme.Light ? 'light' : 'dark');
- EnumeratePlugins (PluginType.Header, (plugin) => {
- plugin.registerButtons ({
- createHeaderButton : (icon, title, link) => {
- this.CreateHeaderButton (icon, title, link);
+ EnumeratePlugins(PluginType.Header, (plugin) => {
+ plugin.registerButtons({
+ createHeaderButton: (icon, title, link) => {
+ this.CreateHeaderButton(icon, title, link);
}
});
});
- this.InitViewer ();
- this.InitToolbar ();
- this.InitDragAndDrop ();
- this.InitSidebar ();
- this.InitNavigator ();
- this.InitCookieConsent ();
+ this.InitViewer();
+ this.InitToolbar();
+ this.InitDragAndDrop();
+ this.InitSidebar();
+ this.InitNavigator();
+ this.InitCookieConsent();
- this.viewer.SetMouseClickHandler (this.OnModelClicked.bind (this));
- this.viewer.SetMouseMoveHandler (this.OnModelMouseMoved.bind (this));
- this.viewer.SetContextMenuHandler (this.OnModelContextMenu.bind (this));
+ this.viewer.SetMouseClickHandler(this.OnModelClicked.bind(this));
+ this.viewer.SetMouseMoveHandler(this.OnModelMouseMoved.bind(this));
+ this.viewer.SetContextMenuHandler(this.OnModelContextMenu.bind(this));
- this.layouter.Init ();
- this.SetUIState (WebsiteUIState.Intro);
+ this.layouter.Init();
+ this.SetUIState(WebsiteUIState.Intro);
- this.hashHandler.SetEventListener (this.OnHashChange.bind (this));
- this.OnHashChange ();
+ this.hashHandler.SetEventListener(this.OnHashChange.bind(this));
+ this.OnHashChange();
- window.addEventListener ('resize', () => {
- this.layouter.Resize ();
- });
+ window.addEventListener('resize', () => {
+ this.layouter.Resize();
+ });
}
- HasLoadedModel ()
- {
+ HasLoadedModel() {
return this.model !== null;
}
- SetUIState (uiState)
- {
- function ShowOnlyOnModelElements (show)
- {
- let root = document.querySelector (':root');
- root.style.setProperty ('--ov_only_on_model_display', show ? 'inherit' : 'none');
+ SetUIState(uiState) {
+ function ShowOnlyOnModelElements(show) {
+ let root = document.querySelector(':root');
+ root.style.setProperty('--ov_only_on_model_display', show ? 'inherit' : 'none');
}
if (this.uiState === uiState) {
@@ -257,301 +253,282 @@ export class Website
this.uiState = uiState;
if (this.uiState === WebsiteUIState.Intro) {
- ShowDomElement (this.parameters.introDiv, true);
- ShowDomElement (this.parameters.headerDiv, true);
- ShowDomElement (this.parameters.mainDiv, false);
- ShowOnlyOnModelElements (false);
+ ShowDomElement(this.parameters.introDiv, true);
+ ShowDomElement(this.parameters.headerDiv, true);
+ ShowDomElement(this.parameters.mainDiv, false);
+ ShowOnlyOnModelElements(false);
} else if (this.uiState === WebsiteUIState.Model) {
- ShowDomElement (this.parameters.introDiv, false);
- ShowDomElement (this.parameters.headerDiv, true);
- ShowDomElement (this.parameters.mainDiv, true);
- ShowOnlyOnModelElements (true);
- this.UpdatePanelsVisibility ();
+ ShowDomElement(this.parameters.introDiv, false);
+ ShowDomElement(this.parameters.headerDiv, true);
+ ShowDomElement(this.parameters.mainDiv, true);
+ ShowOnlyOnModelElements(true);
+ this.UpdatePanelsVisibility();
} else if (this.uiState === WebsiteUIState.Loading) {
- ShowDomElement (this.parameters.introDiv, false);
- ShowDomElement (this.parameters.headerDiv, true);
- ShowDomElement (this.parameters.mainDiv, false);
- ShowOnlyOnModelElements (false);
+ ShowDomElement(this.parameters.introDiv, false);
+ ShowDomElement(this.parameters.headerDiv, true);
+ ShowDomElement(this.parameters.mainDiv, false);
+ ShowOnlyOnModelElements(false);
}
- this.layouter.Resize ();
+ this.layouter.Resize();
}
- ClearModel ()
- {
- CloseAllDialogs ();
+ ClearModel() {
+ CloseAllDialogs();
this.model = null;
- this.viewer.Clear ();
+ this.viewer.Clear();
this.parameters.fileNameDiv.innerHTML = '';
- this.navigator.Clear ();
- this.sidebar.Clear ();
+ this.navigator.Clear();
+ this.sidebar.Clear();
- this.measureTool.SetActive (false);
+ this.measureTool.SetActive(false);
+ this.explodeTool.SetActive(false);
}
- OnModelLoaded (importResult, threeObject)
- {
+ OnModelLoaded(importResult, threeObject) {
this.model = importResult.model;
this.parameters.fileNameDiv.innerHTML = importResult.mainFile;
- this.viewer.SetMainObject (threeObject);
- this.viewer.SetUpVector (Direction.Y, false);
- this.navigator.FillTree (importResult);
- this.sidebar.UpdateControlsVisibility ();
- this.FitModelToWindow (true);
+ this.viewer.SetMainObject(threeObject);
+ this.viewer.SetUpVector(Direction.Y, false);
+ this.navigator.FillTree(importResult);
+ this.sidebar.UpdateControlsVisibility();
+ this.explodeTool.UpdateButtonVisibility();
+ this.FitModelToWindow(true);
}
- OnModelClicked (button, mouseCoordinates)
- {
+ OnModelClicked(button, mouseCoordinates) {
if (button !== 1) {
return;
}
- if (this.measureTool.IsActive ()) {
- this.measureTool.Click (mouseCoordinates);
+ if (this.measureTool.IsActive()) {
+ this.measureTool.Click(mouseCoordinates);
return;
}
- let meshUserData = this.viewer.GetMeshUserDataUnderMouse (IntersectionMode.MeshAndLine, mouseCoordinates);
+ let meshUserData = this.viewer.GetMeshUserDataUnderMouse(IntersectionMode.MeshAndLine, mouseCoordinates);
if (meshUserData === null) {
- this.navigator.SetSelection (null);
+ this.navigator.SetSelection(null);
} else {
- this.navigator.SetSelection (new Selection (SelectionType.Mesh, meshUserData.originalMeshInstance.id));
+ this.navigator.SetSelection(new Selection(SelectionType.Mesh, meshUserData.originalMeshInstance.id));
}
}
- OnModelMouseMoved (mouseCoordinates)
- {
- if (this.measureTool.IsActive ()) {
- this.measureTool.MouseMove (mouseCoordinates);
+ OnModelMouseMoved(mouseCoordinates) {
+ if (this.measureTool.IsActive()) {
+ this.measureTool.MouseMove(mouseCoordinates);
}
}
- OnModelContextMenu (globalMouseCoordinates, mouseCoordinates)
- {
- let meshUserData = this.viewer.GetMeshUserDataUnderMouse (IntersectionMode.MeshAndLine, mouseCoordinates);
+ OnModelContextMenu(globalMouseCoordinates, mouseCoordinates) {
+ let meshUserData = this.viewer.GetMeshUserDataUnderMouse(IntersectionMode.MeshAndLine, mouseCoordinates);
let items = [];
if (meshUserData === null) {
- items.push ({
- name : Loc ('Fit model to window'),
- icon : 'fit',
- onClick : () => {
- this.FitModelToWindow (false);
+ items.push({
+ name: Loc('Fit model to window'),
+ icon: 'fit',
+ onClick: () => {
+ this.FitModelToWindow(false);
}
});
- if (this.navigator.HasHiddenMesh ()) {
- items.push ({
- name : Loc ('Show all meshes'),
- icon : 'visible',
- onClick : () => {
- this.navigator.ShowAllMeshes (true);
+ if (this.navigator.HasHiddenMesh()) {
+ items.push({
+ name: Loc('Show all meshes'),
+ icon: 'visible',
+ onClick: () => {
+ this.navigator.ShowAllMeshes(true);
}
});
}
} else {
- items.push ({
- name : Loc ('Hide mesh'),
- icon : 'hidden',
- onClick : () => {
- this.navigator.ToggleMeshVisibility (meshUserData.originalMeshInstance.id);
+ items.push({
+ name: Loc('Hide mesh'),
+ icon: 'hidden',
+ onClick: () => {
+ this.navigator.ToggleMeshVisibility(meshUserData.originalMeshInstance.id);
}
});
- items.push ({
- name : Loc ('Fit mesh to window'),
- icon : 'fit',
- onClick : () => {
- this.navigator.FitMeshToWindow (meshUserData.originalMeshInstance.id);
+ items.push({
+ name: Loc('Fit mesh to window'),
+ icon: 'fit',
+ onClick: () => {
+ this.navigator.FitMeshToWindow(meshUserData.originalMeshInstance.id);
}
});
- if (this.navigator.MeshItemCount () > 1) {
- let isMeshIsolated = this.navigator.IsMeshIsolated (meshUserData.originalMeshInstance.id);
- items.push ({
- name : isMeshIsolated ? Loc ('Remove isolation') : Loc ('Isolate mesh'),
- icon : isMeshIsolated ? 'deisolate' : 'isolate',
- onClick : () => {
+ if (this.navigator.MeshItemCount() > 1) {
+ let isMeshIsolated = this.navigator.IsMeshIsolated(meshUserData.originalMeshInstance.id);
+ items.push({
+ name: isMeshIsolated ? Loc('Remove isolation') : Loc('Isolate mesh'),
+ icon: isMeshIsolated ? 'deisolate' : 'isolate',
+ onClick: () => {
if (isMeshIsolated) {
- this.navigator.ShowAllMeshes (true);
+ this.navigator.ShowAllMeshes(true);
} else {
- this.navigator.IsolateMesh (meshUserData.originalMeshInstance.id);
+ this.navigator.IsolateMesh(meshUserData.originalMeshInstance.id);
}
}
});
}
}
- ShowListPopup (items, {
- calculatePosition : (contentDiv) => {
- return CalculatePopupPositionToScreen (globalMouseCoordinates, contentDiv);
+ ShowListPopup(items, {
+ calculatePosition: (contentDiv) => {
+ return CalculatePopupPositionToScreen(globalMouseCoordinates, contentDiv);
},
- onClick : (index) => {
+ onClick: (index) => {
let clickedItem = items[index];
- clickedItem.onClick ();
+ clickedItem.onClick();
}
});
}
- OnHashChange ()
- {
- if (this.hashHandler.HasHash ()) {
- let urls = this.hashHandler.GetModelFilesFromHash ();
+ OnHashChange() {
+ if (this.hashHandler.HasHash()) {
+ let urls = this.hashHandler.GetModelFilesFromHash();
if (urls === null) {
return;
}
- TransformFileHostUrls (urls);
- let importSettings = new ImportSettings ();
+ TransformFileHostUrls(urls);
+ let importSettings = new ImportSettings();
importSettings.defaultLineColor = this.settings.defaultLineColor;
importSettings.defaultColor = this.settings.defaultColor;
- let defaultColor = this.hashHandler.GetDefaultColorFromHash ();
+ let defaultColor = this.hashHandler.GetDefaultColorFromHash();
if (defaultColor !== null) {
importSettings.defaultColor = defaultColor;
}
- HandleEvent ('model_load_started', 'hash');
- this.LoadModelFromUrlList (urls, importSettings);
+ HandleEvent('model_load_started', 'hash');
+ this.LoadModelFromUrlList(urls, importSettings);
} else {
- this.ClearModel ();
- this.SetUIState (WebsiteUIState.Intro);
+ this.ClearModel();
+ this.SetUIState(WebsiteUIState.Intro);
}
}
- OpenFileBrowserDialog ()
- {
- this.parameters.fileInput.click ();
+ OpenFileBrowserDialog() {
+ this.parameters.fileInput.click();
}
- FitModelToWindow (onLoad)
- {
+ FitModelToWindow(onLoad) {
let animation = !onLoad;
- let boundingSphere = this.viewer.GetBoundingSphere ((meshUserData) => {
- return this.navigator.IsMeshVisible (meshUserData.originalMeshInstance.id);
+ let boundingSphere = this.viewer.GetBoundingSphere((meshUserData) => {
+ return this.navigator.IsMeshVisible(meshUserData.originalMeshInstance.id);
});
if (onLoad) {
- this.viewer.AdjustClippingPlanesToSphere (boundingSphere);
+ this.viewer.AdjustClippingPlanesToSphere(boundingSphere);
}
- this.viewer.FitSphereToWindow (boundingSphere, animation);
+ this.viewer.FitSphereToWindow(boundingSphere, animation);
}
- FitMeshToWindow (meshInstanceId)
- {
- let boundingSphere = this.viewer.GetBoundingSphere ((meshUserData) => {
- return meshUserData.originalMeshInstance.id.IsEqual (meshInstanceId);
+ FitMeshToWindow(meshInstanceId) {
+ let boundingSphere = this.viewer.GetBoundingSphere((meshUserData) => {
+ return meshUserData.originalMeshInstance.id.IsEqual(meshInstanceId);
});
- this.viewer.FitSphereToWindow (boundingSphere, true);
+ this.viewer.FitSphereToWindow(boundingSphere, true);
}
- FitMeshesToWindow (meshInstanceIdSet)
- {
- let meshInstanceIdKeys = new Set ();
+ FitMeshesToWindow(meshInstanceIdSet) {
+ let meshInstanceIdKeys = new Set();
for (let meshInstanceId of meshInstanceIdSet) {
- meshInstanceIdKeys.add (meshInstanceId.GetKey ());
+ meshInstanceIdKeys.add(meshInstanceId.GetKey());
}
- let boundingSphere = this.viewer.GetBoundingSphere ((meshUserData) => {
- return meshInstanceIdKeys.has (meshUserData.originalMeshInstance.id.GetKey ());
+ let boundingSphere = this.viewer.GetBoundingSphere((meshUserData) => {
+ return meshInstanceIdKeys.has(meshUserData.originalMeshInstance.id.GetKey());
});
- this.viewer.FitSphereToWindow (boundingSphere, true);
+ this.viewer.FitSphereToWindow(boundingSphere, true);
}
- UpdateMeshesVisibility ()
- {
- this.viewer.SetMeshesVisibility ((meshUserData) => {
- return this.navigator.IsMeshVisible (meshUserData.originalMeshInstance.id);
+ UpdateMeshesVisibility() {
+ this.viewer.SetMeshesVisibility((meshUserData) => {
+ return this.navigator.IsMeshVisible(meshUserData.originalMeshInstance.id);
});
}
- UpdateMeshesSelection ()
- {
- let selectedMeshId = this.navigator.GetSelectedMeshId ();
- this.viewer.SetMeshesHighlight (this.highlightColor, (meshUserData) => {
- if (selectedMeshId !== null && meshUserData.originalMeshInstance.id.IsEqual (selectedMeshId)) {
+ UpdateMeshesSelection() {
+ let selectedMeshId = this.navigator.GetSelectedMeshId();
+ this.viewer.SetMeshesHighlight(this.highlightColor, (meshUserData) => {
+ if (selectedMeshId !== null && meshUserData.originalMeshInstance.id.IsEqual(selectedMeshId)) {
return true;
}
return false;
});
}
- LoadModelFromUrlList (urls, settings)
- {
- let inputFiles = InputFilesFromUrls (urls);
- this.LoadModelFromInputFiles (inputFiles, settings);
- this.ClearHashIfNotOnlyUrlList ();
+ LoadModelFromUrlList(urls, settings) {
+ let inputFiles = InputFilesFromUrls(urls);
+ this.LoadModelFromInputFiles(inputFiles, settings);
+ this.ClearHashIfNotOnlyUrlList();
}
- LoadModelFromFileList (files)
- {
- let importSettings = new ImportSettings ();
+ LoadModelFromFileList(files) {
+ let importSettings = new ImportSettings();
importSettings.defaultLineColor = this.settings.defaultLineColor;
importSettings.defaultColor = this.settings.defaultColor;
- let inputFiles = InputFilesFromFileObjects (files);
- this.LoadModelFromInputFiles (inputFiles, importSettings);
- this.ClearHashIfNotOnlyUrlList ();
- }
-
- LoadModelFromInputFiles (files, settings)
- {
- this.modelLoaderUI.LoadModel (files, settings, {
- onStart : () =>
- {
- this.SetUIState (WebsiteUIState.Loading);
- this.ClearModel ();
+ let inputFiles = InputFilesFromFileObjects(files);
+ this.LoadModelFromInputFiles(inputFiles, importSettings);
+ this.ClearHashIfNotOnlyUrlList();
+ }
+
+ LoadModelFromInputFiles(files, settings) {
+ this.modelLoaderUI.LoadModel(files, settings, {
+ onStart: () => {
+ this.SetUIState(WebsiteUIState.Loading);
+ this.ClearModel();
},
- onFinish : (importResult, threeObject) =>
- {
- this.SetUIState (WebsiteUIState.Model);
- this.OnModelLoaded (importResult, threeObject);
- let importedExtension = GetFileExtension (importResult.mainFile);
- HandleEvent ('model_loaded', importedExtension);
+ onFinish: (importResult, threeObject) => {
+ this.SetUIState(WebsiteUIState.Model);
+ this.OnModelLoaded(importResult, threeObject);
+ let importedExtension = GetFileExtension(importResult.mainFile);
+ HandleEvent('model_loaded', importedExtension);
},
- onRender : () =>
- {
- this.viewer.Render ();
+ onRender: () => {
+ this.viewer.Render();
},
- onError : (importError) =>
- {
- this.SetUIState (WebsiteUIState.Intro);
+ onError: (importError) => {
+ this.SetUIState(WebsiteUIState.Intro);
let extensionStr = null;
if (importError.mainFile !== null) {
- extensionStr = GetFileExtension (importError.mainFile);
+ extensionStr = GetFileExtension(importError.mainFile);
} else {
let extensions = [];
- let importer = this.modelLoaderUI.GetImporter ();
- let fileList = importer.GetFileList ().GetFiles ();
+ let importer = this.modelLoaderUI.GetImporter();
+ let fileList = importer.GetFileList().GetFiles();
for (let i = 0; i < fileList.length; i++) {
let extension = fileList[i].extension;
- extensions.push (extension);
+ extensions.push(extension);
}
- extensionStr = extensions.join (',');
+ extensionStr = extensions.join(',');
}
if (importError.code === ImportErrorCode.NoImportableFile) {
- HandleEvent ('no_importable_file', extensionStr);
+ HandleEvent('no_importable_file', extensionStr);
} else if (importError.code === ImportErrorCode.FailedToLoadFile) {
- HandleEvent ('failed_to_load_file', extensionStr);
+ HandleEvent('failed_to_load_file', extensionStr);
} else if (importError.code === ImportErrorCode.ImportFailed) {
- HandleEvent ('import_failed', extensionStr, {
- error_message : importError.message
+ HandleEvent('import_failed', extensionStr, {
+ error_message: importError.message
});
}
}
});
}
- ClearHashIfNotOnlyUrlList ()
- {
- let importer = this.modelLoaderUI.GetImporter ();
- let isOnlyUrl = importer.GetFileList ().IsOnlyUrlSource ();
- if (!isOnlyUrl && this.hashHandler.HasHash ()) {
- this.hashHandler.SkipNextEventHandler ();
- this.hashHandler.ClearHash ();
+ ClearHashIfNotOnlyUrlList() {
+ let importer = this.modelLoaderUI.GetImporter();
+ let isOnlyUrl = importer.GetFileList().IsOnlyUrlSource();
+ if (!isOnlyUrl && this.hashHandler.HasHash()) {
+ this.hashHandler.SkipNextEventHandler();
+ this.hashHandler.ClearHash();
}
}
- UpdateEdgeDisplay ()
- {
- this.settings.SaveToCookies ();
- this.viewer.SetEdgeSettings (this.settings.edgeSettings);
+ UpdateEdgeDisplay() {
+ this.settings.SaveToCookies();
+ this.viewer.SetEdgeSettings(this.settings.edgeSettings);
+ this.explodeTool.RefreshEdges();
}
- UpdateEnvironmentMap ()
- {
+ UpdateEnvironmentMap() {
let envMapPath = 'assets/envmaps/' + this.settings.environmentMapName + '/';
let envMapTextures = [
envMapPath + 'posx.jpg',
@@ -561,416 +538,410 @@ export class Website
envMapPath + 'posz.jpg',
envMapPath + 'negz.jpg'
];
- let environmentSettings = new EnvironmentSettings (envMapTextures, this.settings.backgroundIsEnvMap);
- this.viewer.SetEnvironmentMapSettings (environmentSettings);
+ let environmentSettings = new EnvironmentSettings(envMapTextures, this.settings.backgroundIsEnvMap);
+ this.viewer.SetEnvironmentMapSettings(environmentSettings);
}
- SwitchTheme (newThemeId, resetColors)
- {
+ SwitchTheme(newThemeId, resetColors) {
this.settings.themeId = newThemeId;
- this.themeHandler.SwitchTheme (this.settings.themeId);
+ this.themeHandler.SwitchTheme(this.settings.themeId);
if (resetColors) {
- let defaultSettings = new Settings (this.settings.themeId);
+ let defaultSettings = new Settings(this.settings.themeId);
this.settings.backgroundColor = defaultSettings.backgroundColor;
this.settings.defaultLineColor = defaultSettings.defaultLineColor;
this.settings.defaultColor = defaultSettings.defaultColor;
- this.sidebar.UpdateControlsStatus ();
+ this.sidebar.UpdateControlsStatus();
- this.viewer.SetBackgroundColor (this.settings.backgroundColor);
- let modelLoader = this.modelLoaderUI.GetModelLoader ();
- if (modelLoader.GetDefaultMaterials () !== null) {
- ReplaceDefaultMaterialsColor (this.model, this.settings.defaultColor, this.settings.defaultLineColor);
- modelLoader.ReplaceDefaultMaterialsColor (this.settings.defaultColor, this.settings.defaultLineColor);
+ this.viewer.SetBackgroundColor(this.settings.backgroundColor);
+ let modelLoader = this.modelLoaderUI.GetModelLoader();
+ if (modelLoader.GetDefaultMaterials() !== null) {
+ ReplaceDefaultMaterialsColor(this.model, this.settings.defaultColor, this.settings.defaultLineColor);
+ modelLoader.ReplaceDefaultMaterialsColor(this.settings.defaultColor, this.settings.defaultLineColor);
}
}
- this.settings.SaveToCookies ();
+ this.settings.SaveToCookies();
}
- InitViewer ()
- {
- let canvas = AddDomElement (this.parameters.viewerDiv, 'canvas');
- this.viewer.Init (canvas);
- this.viewer.SetEdgeSettings (this.settings.edgeSettings);
- this.viewer.SetBackgroundColor (this.settings.backgroundColor);
- this.viewer.SetNavigationMode (this.cameraSettings.navigationMode);
- this.viewer.SetProjectionMode (this.cameraSettings.projectionMode);
- this.UpdateEnvironmentMap ();
+ InitViewer() {
+ let canvas = AddDomElement(this.parameters.viewerDiv, 'canvas');
+ this.viewer.Init(canvas);
+ this.viewer.SetEdgeSettings(this.settings.edgeSettings);
+ this.viewer.SetBackgroundColor(this.settings.backgroundColor);
+ this.viewer.SetNavigationMode(this.cameraSettings.navigationMode);
+ this.viewer.SetProjectionMode(this.cameraSettings.projectionMode);
+ this.UpdateEnvironmentMap();
}
- InitToolbar ()
- {
- function AddButton (toolbar, imageName, imageTitle, classNames, onClick)
- {
- let button = toolbar.AddImageButton (imageName, imageTitle, () => {
- onClick ();
+ InitToolbar() {
+ function AddButton(toolbar, imageName, imageTitle, classNames, onClick) {
+ let button = toolbar.AddImageButton(imageName, imageTitle, () => {
+ onClick();
});
for (let className of classNames) {
- button.AddClass (className);
+ button.AddClass(className);
}
return button;
}
- function AddPushButton (toolbar, imageName, imageTitle, classNames, onClick)
- {
- let button = toolbar.AddImagePushButton (imageName, imageTitle, false, (isSelected) => {
- onClick (isSelected);
+ function AddPushButton(toolbar, imageName, imageTitle, classNames, onClick) {
+ let button = toolbar.AddImagePushButton(imageName, imageTitle, false, (isSelected) => {
+ onClick(isSelected);
});
for (let className of classNames) {
- button.AddClass (className);
+ button.AddClass(className);
}
return button;
}
- function AddRadioButton (toolbar, imageNames, imageTitles, selectedIndex, classNames, onClick)
- {
+ function AddRadioButton(toolbar, imageNames, imageTitles, selectedIndex, classNames, onClick) {
let imageData = [];
for (let i = 0; i < imageNames.length; i++) {
let imageName = imageNames[i];
let imageTitle = imageTitles[i];
- imageData.push ({
- image : imageName,
- title : imageTitle
+ imageData.push({
+ image: imageName,
+ title: imageTitle
});
}
- let buttons = toolbar.AddImageRadioButton (imageData, selectedIndex, (buttonIndex) => {
- onClick (buttonIndex);
+ let buttons = toolbar.AddImageRadioButton(imageData, selectedIndex, (buttonIndex) => {
+ onClick(buttonIndex);
});
for (let className of classNames) {
for (let button of buttons) {
- button.AddClass (className);
+ button.AddClass(className);
}
}
}
- function AddSeparator (toolbar, classNames)
- {
- let separator = toolbar.AddSeparator ();
+ function AddSeparator(toolbar, classNames) {
+ let separator = toolbar.AddSeparator();
if (classNames !== null) {
for (let className of classNames) {
- separator.classList.add (className);
+ separator.classList.add(className);
}
}
+ return separator;
}
- let importer = this.modelLoaderUI.GetImporter ();
+ let importer = this.modelLoaderUI.GetImporter();
let navigationModeIndex = (this.cameraSettings.navigationMode === NavigationMode.FixedUpVector ? 0 : 1);
let projectionModeIndex = (this.cameraSettings.projectionMode === ProjectionMode.Perspective ? 0 : 1);
- AddButton (this.toolbar, 'open', Loc ('Open from your device'), [], () => {
- this.OpenFileBrowserDialog ();
+ AddButton(this.toolbar, 'open', Loc('Open from your device'), [], () => {
+ this.OpenFileBrowserDialog();
});
- AddButton (this.toolbar, 'open_url', Loc ('Open from url'), [], () => {
- ShowOpenUrlDialog ((urls) => {
+ AddButton(this.toolbar, 'open_url', Loc('Open from url'), [], () => {
+ ShowOpenUrlDialog((urls) => {
if (urls.length > 0) {
- this.hashHandler.SetModelFilesToHash (urls);
+ this.hashHandler.SetModelFilesToHash(urls);
}
});
});
- AddSeparator (this.toolbar, ['only_on_model']);
- AddButton (this.toolbar, 'fit', Loc ('Fit model to window'), ['only_on_model'], () => {
- this.FitModelToWindow (false);
+ AddSeparator(this.toolbar, ['only_on_model']);
+ AddButton(this.toolbar, 'fit', Loc('Fit model to window'), ['only_on_model'], () => {
+ this.FitModelToWindow(false);
});
- AddButton (this.toolbar, 'up_y', Loc ('Set Y axis as up vector'), ['only_on_model'], () => {
- this.viewer.SetUpVector (Direction.Y, true);
+ AddButton(this.toolbar, 'up_y', Loc('Set Y axis as up vector'), ['only_on_model'], () => {
+ this.viewer.SetUpVector(Direction.Y, true);
});
- AddButton (this.toolbar, 'up_z', Loc ('Set Z axis as up vector'), ['only_on_model'], () => {
- this.viewer.SetUpVector (Direction.Z, true);
+ AddButton(this.toolbar, 'up_z', Loc('Set Z axis as up vector'), ['only_on_model'], () => {
+ this.viewer.SetUpVector(Direction.Z, true);
});
- AddButton (this.toolbar, 'flip', Loc ('Flip up vector'), ['only_on_model'], () => {
- this.viewer.FlipUpVector ();
+ AddButton(this.toolbar, 'flip', Loc('Flip up vector'), ['only_on_model'], () => {
+ this.viewer.FlipUpVector();
});
- AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
- AddRadioButton (this.toolbar, ['fix_up_on', 'fix_up_off'], [Loc ('Fixed up vector'), Loc ('Free orbit')], navigationModeIndex, ['only_full_width', 'only_on_model'], (buttonIndex) => {
+ AddSeparator(this.toolbar, ['only_full_width', 'only_on_model']);
+ AddRadioButton(this.toolbar, ['fix_up_on', 'fix_up_off'], [Loc('Fixed up vector'), Loc('Free orbit')], navigationModeIndex, ['only_full_width', 'only_on_model'], (buttonIndex) => {
if (buttonIndex === 0) {
this.cameraSettings.navigationMode = NavigationMode.FixedUpVector;
} else if (buttonIndex === 1) {
this.cameraSettings.navigationMode = NavigationMode.FreeOrbit;
}
- this.cameraSettings.SaveToCookies ();
- this.viewer.SetNavigationMode (this.cameraSettings.navigationMode);
+ this.cameraSettings.SaveToCookies();
+ this.viewer.SetNavigationMode(this.cameraSettings.navigationMode);
});
- AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
- AddRadioButton (this.toolbar, ['camera_perspective', 'camera_orthographic'], [Loc ('Perspective camera'), Loc ('Orthographic camera')], projectionModeIndex, ['only_full_width', 'only_on_model'], (buttonIndex) => {
+ AddSeparator(this.toolbar, ['only_full_width', 'only_on_model']);
+ AddRadioButton(this.toolbar, ['camera_perspective', 'camera_orthographic'], [Loc('Perspective camera'), Loc('Orthographic camera')], projectionModeIndex, ['only_full_width', 'only_on_model'], (buttonIndex) => {
if (buttonIndex === 0) {
this.cameraSettings.projectionMode = ProjectionMode.Perspective;
} else if (buttonIndex === 1) {
this.cameraSettings.projectionMode = ProjectionMode.Orthographic;
}
- this.cameraSettings.SaveToCookies ();
- this.viewer.SetProjectionMode (this.cameraSettings.projectionMode);
- this.sidebar.UpdateControlsVisibility ();
- });
- AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
- let measureToolButton = AddPushButton (this.toolbar, 'measure', Loc ('Measure'), ['only_full_width', 'only_on_model'], (isSelected) => {
- HandleEvent ('measure_tool_activated', isSelected ? 'on' : 'off');
- this.navigator.SetSelection (null);
- this.measureTool.SetActive (isSelected);
- });
- this.measureTool.SetButton (measureToolButton);
- AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
- AddButton (this.toolbar, 'download', Loc ('Download'), ['only_full_width', 'only_on_model'], () => {
- HandleEvent ('model_downloaded', '');
- let importer = this.modelLoaderUI.GetImporter ();
- DownloadModel (importer);
- });
- AddButton (this.toolbar, 'export', Loc ('Export'), ['only_full_width', 'only_on_model'], () => {
- ShowExportDialog (this.model, this.viewer, {
- isMeshVisible : (meshInstanceId) => {
- return this.navigator.IsMeshVisible (meshInstanceId);
+ this.cameraSettings.SaveToCookies();
+ this.viewer.SetProjectionMode(this.cameraSettings.projectionMode);
+ this.sidebar.UpdateControlsVisibility();
+ });
+ AddSeparator(this.toolbar, ['only_full_width', 'only_on_model']);
+ let measureToolButton = AddPushButton(this.toolbar, 'measure', Loc('Measure'), ['only_full_width', 'only_on_model'], (isSelected) => {
+ HandleEvent('measure_tool_activated', isSelected ? 'on' : 'off');
+ this.navigator.SetSelection(null);
+ this.measureTool.SetActive(isSelected);
+ });
+ this.measureTool.SetButton(measureToolButton);
+ let explodeSeparator = AddSeparator(this.toolbar, ['only_full_width', 'only_on_model']);
+ let explodeToolButton = AddPushButton(this.toolbar, 'explode', Loc('Explode View'), ['only_full_width', 'only_on_model'], (isSelected) => {
+ this.navigator.SetSelection(null);
+ this.explodeTool.SetActive(isSelected);
+ });
+ this.explodeTool.SetButton(explodeToolButton);
+ this.explodeTool.SetSeparator(explodeSeparator);
+ // Initially hide if there's no model or only one mesh
+ explodeToolButton.AddClass('ov_hidden');
+ explodeSeparator.classList.add('ov_hidden');
+ AddSeparator(this.toolbar, ['only_full_width', 'only_on_model']);
+ AddButton(this.toolbar, 'download', Loc('Download'), ['only_full_width', 'only_on_model'], () => {
+ HandleEvent('model_downloaded', '');
+ let importer = this.modelLoaderUI.GetImporter();
+ DownloadModel(importer);
+ });
+ AddButton(this.toolbar, 'export', Loc('Export'), ['only_full_width', 'only_on_model'], () => {
+ ShowExportDialog(this.model, this.viewer, {
+ isMeshVisible: (meshInstanceId) => {
+ return this.navigator.IsMeshVisible(meshInstanceId);
}
});
});
- AddButton (this.toolbar, 'share', Loc ('Share'), ['only_full_width', 'only_on_model'], () => {
- ShowSharingDialog (importer.GetFileList (), this.settings, this.viewer);
+ AddButton(this.toolbar, 'share', Loc('Share'), ['only_full_width', 'only_on_model'], () => {
+ ShowSharingDialog(importer.GetFileList(), this.settings, this.viewer);
});
- AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
- AddButton (this.toolbar, 'snapshot', Loc ('Create snapshot'), ['only_full_width', 'only_on_model'], () => {
- ShowSnapshotDialog (this.viewer);
+ AddSeparator(this.toolbar, ['only_full_width', 'only_on_model']);
+ AddButton(this.toolbar, 'snapshot', Loc('Create snapshot'), ['only_full_width', 'only_on_model'], () => {
+ ShowSnapshotDialog(this.viewer);
});
- EnumeratePlugins (PluginType.Toolbar, (plugin) => {
- plugin.registerButtons ({
- createSeparator : (classNames) => {
- AddSeparator (this.toolbar, classNames);
+ EnumeratePlugins(PluginType.Toolbar, (plugin) => {
+ plugin.registerButtons({
+ createSeparator: (classNames) => {
+ AddSeparator(this.toolbar, classNames);
},
- createButton : (icon, title, classNames, onClick) => {
- AddButton (this.toolbar, icon, title, classNames, onClick);
+ createButton: (icon, title, classNames, onClick) => {
+ AddButton(this.toolbar, icon, title, classNames, onClick);
},
- getModel : () => {
+ getModel: () => {
return this.model;
}
});
});
let selectedTheme = (this.settings.themeId === Theme.Light ? 1 : 0);
- AddRadioButton (this.toolbar, ['dark_mode', 'light_mode'], [Loc ('Dark mode'), Loc ('Light mode')], selectedTheme, ['align_right'], (buttonIndex) => {
+ AddRadioButton(this.toolbar, ['dark_mode', 'light_mode'], [Loc('Dark mode'), Loc('Light mode')], selectedTheme, ['align_right'], (buttonIndex) => {
if (buttonIndex === 0) {
this.settings.themeId = Theme.Dark;
} else if (buttonIndex === 1) {
this.settings.themeId = Theme.Light;
}
- HandleEvent ('theme_changed', this.settings.themeId === Theme.Light ? 'light' : 'dark');
- this.SwitchTheme (this.settings.themeId, true);
+ HandleEvent('theme_changed', this.settings.themeId === Theme.Light ? 'light' : 'dark');
+ this.SwitchTheme(this.settings.themeId, true);
});
- this.parameters.fileInput.addEventListener ('change', (ev) => {
+ this.parameters.fileInput.addEventListener('change', (ev) => {
if (ev.target.files.length > 0) {
- HandleEvent ('model_load_started', 'open_file');
- this.LoadModelFromFileList (ev.target.files);
+ HandleEvent('model_load_started', 'open_file');
+ this.LoadModelFromFileList(ev.target.files);
}
});
}
- InitDragAndDrop ()
- {
- window.addEventListener ('dragstart', (ev) => {
- ev.preventDefault ();
+ InitDragAndDrop() {
+ window.addEventListener('dragstart', (ev) => {
+ ev.preventDefault();
}, false);
- window.addEventListener ('dragover', (ev) => {
- ev.stopPropagation ();
- ev.preventDefault ();
+ window.addEventListener('dragover', (ev) => {
+ ev.stopPropagation();
+ ev.preventDefault();
ev.dataTransfer.dropEffect = 'copy';
}, false);
- window.addEventListener ('drop', (ev) => {
- ev.stopPropagation ();
- ev.preventDefault ();
- GetFilesFromDataTransfer (ev.dataTransfer, (files) => {
+ window.addEventListener('drop', (ev) => {
+ ev.stopPropagation();
+ ev.preventDefault();
+ GetFilesFromDataTransfer(ev.dataTransfer, (files) => {
if (files.length > 0) {
- HandleEvent ('model_load_started', 'drop');
- this.LoadModelFromFileList (files);
+ HandleEvent('model_load_started', 'drop');
+ this.LoadModelFromFileList(files);
}
});
}, false);
}
- InitSidebar ()
- {
- this.sidebar.Init ({
- getShadingType : () => {
- return this.viewer.GetShadingType ();
+ InitSidebar() {
+ this.sidebar.Init({
+ getShadingType: () => {
+ return this.viewer.GetShadingType();
},
- getProjectionMode : () => {
- return this.viewer.GetProjectionMode ();
+ getProjectionMode: () => {
+ return this.viewer.GetProjectionMode();
},
- getDefaultMaterials : () => {
- return GetDefaultMaterials (this.model);
+ getDefaultMaterials: () => {
+ return GetDefaultMaterials(this.model);
},
- onEnvironmentMapChanged : () => {
- this.settings.SaveToCookies ();
- this.UpdateEnvironmentMap ();
- if (this.measureTool.IsActive ()) {
- this.measureTool.UpdatePanel ();
+ onEnvironmentMapChanged: () => {
+ this.settings.SaveToCookies();
+ this.UpdateEnvironmentMap();
+ if (this.measureTool.IsActive()) {
+ this.measureTool.UpdatePanel();
}
},
- onBackgroundColorChanged : () => {
- this.settings.SaveToCookies ();
- this.viewer.SetBackgroundColor (this.settings.backgroundColor);
- if (this.measureTool.IsActive ()) {
- this.measureTool.UpdatePanel ();
+ onBackgroundColorChanged: () => {
+ this.settings.SaveToCookies();
+ this.viewer.SetBackgroundColor(this.settings.backgroundColor);
+ if (this.measureTool.IsActive()) {
+ this.measureTool.UpdatePanel();
}
},
- onDefaultColorChanged : () => {
- this.settings.SaveToCookies ();
- let modelLoader = this.modelLoaderUI.GetModelLoader ();
- if (modelLoader.GetDefaultMaterials () !== null) {
- ReplaceDefaultMaterialsColor (this.model, this.settings.defaultColor, this.settings.defaultLineColor);
- modelLoader.ReplaceDefaultMaterialsColor (this.settings.defaultColor, this.settings.defaultLineColor);
+ onDefaultColorChanged: () => {
+ this.settings.SaveToCookies();
+ let modelLoader = this.modelLoaderUI.GetModelLoader();
+ if (modelLoader.GetDefaultMaterials() !== null) {
+ ReplaceDefaultMaterialsColor(this.model, this.settings.defaultColor, this.settings.defaultLineColor);
+ modelLoader.ReplaceDefaultMaterialsColor(this.settings.defaultColor, this.settings.defaultLineColor);
}
- this.viewer.Render ();
+ this.viewer.Render();
},
- onEdgeDisplayChanged : () => {
- HandleEvent ('edge_display_changed', this.settings.showEdges ? 'on' : 'off');
- this.UpdateEdgeDisplay ();
+ onEdgeDisplayChanged: () => {
+ HandleEvent('edge_display_changed', this.settings.showEdges ? 'on' : 'off');
+ this.UpdateEdgeDisplay();
},
- onResizeRequested : () => {
- this.layouter.Resize ();
+ onResizeRequested: () => {
+ this.layouter.Resize();
},
- onShowHidePanels : (show) => {
- ShowDomElement (this.parameters.sidebarSplitterDiv, show);
- CookieSetBoolVal ('ov_show_sidebar', show);
+ onShowHidePanels: (show) => {
+ ShowDomElement(this.parameters.sidebarSplitterDiv, show);
+ CookieSetBoolVal('ov_show_sidebar', show);
}
});
}
- InitNavigator ()
- {
- function GetMeshUserDataArray (viewer, meshInstanceId)
- {
+ InitNavigator() {
+ function GetMeshUserDataArray(viewer, meshInstanceId) {
let userDataArr = [];
- viewer.EnumerateMeshesAndLinesUserData ((meshUserData) => {
- if (meshUserData.originalMeshInstance.id.IsEqual (meshInstanceId)) {
- userDataArr.push (meshUserData);
+ viewer.EnumerateMeshesAndLinesUserData((meshUserData) => {
+ if (meshUserData.originalMeshInstance.id.IsEqual(meshInstanceId)) {
+ userDataArr.push(meshUserData);
}
});
return userDataArr;
}
- function GetMeshesForMaterial (viewer, materialIndex)
- {
+ function GetMeshesForMaterial(viewer, materialIndex) {
let usedByMeshes = [];
- viewer.EnumerateMeshesAndLinesUserData ((meshUserData) => {
- if (materialIndex === null || meshUserData.originalMaterials.indexOf (materialIndex) !== -1) {
- usedByMeshes.push (meshUserData.originalMeshInstance);
+ viewer.EnumerateMeshesAndLinesUserData((meshUserData) => {
+ if (materialIndex === null || meshUserData.originalMaterials.indexOf(materialIndex) !== -1) {
+ usedByMeshes.push(meshUserData.originalMeshInstance);
}
});
return usedByMeshes;
}
- function GetMaterialReferenceInfo (model, materialIndex)
- {
- const material = model.GetMaterial (materialIndex);
+ function GetMaterialReferenceInfo(model, materialIndex) {
+ const material = model.GetMaterial(materialIndex);
return {
- index : materialIndex,
- name : material.name,
- color : material.color.Clone ()
+ index: materialIndex,
+ name: material.name,
+ color: material.color.Clone()
};
}
- function GetMaterialsForMesh (viewer, model, meshInstanceId)
- {
+ function GetMaterialsForMesh(viewer, model, meshInstanceId) {
let usedMaterials = [];
if (meshInstanceId === null) {
- for (let materialIndex = 0; materialIndex < model.MaterialCount (); materialIndex++) {
- usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex));
+ for (let materialIndex = 0; materialIndex < model.MaterialCount(); materialIndex++) {
+ usedMaterials.push(GetMaterialReferenceInfo(model, materialIndex));
}
} else {
- let userDataArr = GetMeshUserDataArray (viewer, meshInstanceId);
- let addedMaterialIndices = new Set ();
+ let userDataArr = GetMeshUserDataArray(viewer, meshInstanceId);
+ let addedMaterialIndices = new Set();
for (let userData of userDataArr) {
for (let materialIndex of userData.originalMaterials) {
- if (addedMaterialIndices.has (materialIndex)) {
+ if (addedMaterialIndices.has(materialIndex)) {
continue;
}
- usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex));
- addedMaterialIndices.add (materialIndex);
+ usedMaterials.push(GetMaterialReferenceInfo(model, materialIndex));
+ addedMaterialIndices.add(materialIndex);
}
}
}
- usedMaterials.sort ((a, b) => {
+ usedMaterials.sort((a, b) => {
return a.index - b.index;
});
return usedMaterials;
}
- this.navigator.Init ({
- openFileBrowserDialog : () => {
- this.OpenFileBrowserDialog ();
+ this.navigator.Init({
+ openFileBrowserDialog: () => {
+ this.OpenFileBrowserDialog();
},
- fitMeshToWindow : (meshInstanceId) => {
- this.FitMeshToWindow (meshInstanceId);
+ fitMeshToWindow: (meshInstanceId) => {
+ this.FitMeshToWindow(meshInstanceId);
},
- fitMeshesToWindow : (meshInstanceIdSet) => {
- this.FitMeshesToWindow (meshInstanceIdSet);
+ fitMeshesToWindow: (meshInstanceIdSet) => {
+ this.FitMeshesToWindow(meshInstanceIdSet);
},
- getMeshesForMaterial : (materialIndex) => {
- return GetMeshesForMaterial (this.viewer, materialIndex);
+ getMeshesForMaterial: (materialIndex) => {
+ return GetMeshesForMaterial(this.viewer, materialIndex);
},
- getMaterialsForMesh : (meshInstanceId) => {
- return GetMaterialsForMesh (this.viewer, this.model, meshInstanceId);
+ getMaterialsForMesh: (meshInstanceId) => {
+ return GetMaterialsForMesh(this.viewer, this.model, meshInstanceId);
},
- onMeshVisibilityChanged : () => {
- this.UpdateMeshesVisibility ();
+ onMeshVisibilityChanged: () => {
+ this.UpdateMeshesVisibility();
},
- onMeshSelectionChanged : () => {
- this.UpdateMeshesSelection ();
+ onMeshSelectionChanged: () => {
+ this.UpdateMeshesSelection();
},
- onSelectionCleared : () => {
- this.sidebar.AddObject3DProperties (this.model, this.model);
+ onSelectionCleared: () => {
+ this.sidebar.AddObject3DProperties(this.model, this.model);
},
- onMeshSelected : (meshInstanceId) => {
- let meshInstance = this.model.GetMeshInstance (meshInstanceId);
- this.sidebar.AddObject3DProperties (this.model, meshInstance);
+ onMeshSelected: (meshInstanceId) => {
+ let meshInstance = this.model.GetMeshInstance(meshInstanceId);
+ this.sidebar.AddObject3DProperties(this.model, meshInstance);
},
- onMaterialSelected : (materialIndex) => {
- this.sidebar.AddMaterialProperties (this.model.GetMaterial (materialIndex));
+ onMaterialSelected: (materialIndex) => {
+ this.sidebar.AddMaterialProperties(this.model.GetMaterial(materialIndex));
},
- onResizeRequested : () => {
- this.layouter.Resize ();
+ onResizeRequested: () => {
+ this.layouter.Resize();
},
- onShowHidePanels : (show) => {
- ShowDomElement (this.parameters.navigatorSplitterDiv, show);
- CookieSetBoolVal ('ov_show_navigator', show);
+ onShowHidePanels: (show) => {
+ ShowDomElement(this.parameters.navigatorSplitterDiv, show);
+ CookieSetBoolVal('ov_show_navigator', show);
}
});
}
- UpdatePanelsVisibility ()
- {
- let showNavigator = CookieGetBoolVal ('ov_show_navigator', true);
- let showSidebar = CookieGetBoolVal ('ov_show_sidebar', true);
- this.navigator.ShowPanels (showNavigator);
- this.sidebar.ShowPanels (showSidebar);
+ UpdatePanelsVisibility() {
+ let showNavigator = CookieGetBoolVal('ov_show_navigator', true);
+ let showSidebar = CookieGetBoolVal('ov_show_sidebar', true);
+ this.navigator.ShowPanels(showNavigator);
+ this.sidebar.ShowPanels(showSidebar);
}
- CreateHeaderButton (icon, title, link)
- {
- let buttonLink = CreateDomElement ('a');
- buttonLink.setAttribute ('href', link);
- buttonLink.setAttribute ('target', '_blank');
- buttonLink.setAttribute ('rel', 'noopener noreferrer');
- InstallTooltip (buttonLink, title);
- AddSvgIconElement (buttonLink, icon, 'header_button');
- this.parameters.headerButtonsDiv.appendChild (buttonLink);
+ CreateHeaderButton(icon, title, link) {
+ let buttonLink = CreateDomElement('a');
+ buttonLink.setAttribute('href', link);
+ buttonLink.setAttribute('target', '_blank');
+ buttonLink.setAttribute('rel', 'noopener noreferrer');
+ InstallTooltip(buttonLink, title);
+ AddSvgIconElement(buttonLink, icon, 'header_button');
+ this.parameters.headerButtonsDiv.appendChild(buttonLink);
return buttonLink;
}
- InitCookieConsent ()
- {
- let accepted = CookieGetBoolVal ('ov_cookie_consent', false);
+ InitCookieConsent() {
+ let accepted = CookieGetBoolVal('ov_cookie_consent', false);
if (accepted) {
return;
}
- let text = Loc ('This website uses cookies to offer you better user experience. See the details at the Cookies Policy page.');
- let popupDiv = AddDiv (document.body, 'ov_bottom_floating_panel');
- AddDiv (popupDiv, 'ov_floating_panel_text', text);
- let acceptButton = AddDiv (popupDiv, 'ov_button ov_floating_panel_button', Loc ('Accept'));
- acceptButton.addEventListener ('click', () => {
- CookieSetBoolVal ('ov_cookie_consent', true);
- popupDiv.remove ();
+ let text = Loc('This website uses cookies to offer you better user experience. See the details at the Cookies Policy page.');
+ let popupDiv = AddDiv(document.body, 'ov_bottom_floating_panel');
+ AddDiv(popupDiv, 'ov_floating_panel_text', text);
+ let acceptButton = AddDiv(popupDiv, 'ov_button ov_floating_panel_button', Loc('Accept'));
+ acceptButton.addEventListener('click', () => {
+ CookieSetBoolVal('ov_cookie_consent', true);
+ popupDiv.remove();
});
}
}
diff --git a/website/info/css/O3DVIcons.woff b/website/info/css/O3DVIcons.woff
index 2e28dd7c..6c73da0c 100644
Binary files a/website/info/css/O3DVIcons.woff and b/website/info/css/O3DVIcons.woff differ
diff --git a/website/info/css/icons.css b/website/info/css/icons.css
index 05a1f523..82a4d46b 100644
--- a/website/info/css/icons.css
+++ b/website/info/css/icons.css
@@ -1,6 +1,6 @@
@font-face {
font-family: "O3DVIcons";
- src: url("./O3DVIcons.woff?d27bdb5af135068ed4a9350e285e132e") format("woff");
+ src: url("./O3DVIcons.woff?a183607fabf1ae69b129cd0cbb17c310") format("woff");
}
i[class^="icon-"]:before, i[class*=" icon-"]:before {
@@ -56,108 +56,111 @@ i[class^="icon-"]:before, i[class*=" icon-"]:before {
.icon-expand:before {
content: "\f10e";
}
-.icon-export:before {
+.icon-explode:before {
content: "\f10f";
}
-.icon-feedback:before {
+.icon-export:before {
content: "\f110";
}
-.icon-file_download:before {
+.icon-feedback:before {
content: "\f111";
}
-.icon-files:before {
+.icon-file_download:before {
content: "\f112";
}
-.icon-fit:before {
+.icon-files:before {
content: "\f113";
}
-.icon-fix_up_off:before {
+.icon-fit:before {
content: "\f114";
}
-.icon-fix_up_on:before {
+.icon-fix_up_off:before {
content: "\f115";
}
-.icon-flat_list:before {
+.icon-fix_up_on:before {
content: "\f116";
}
-.icon-flip:before {
+.icon-flat_list:before {
content: "\f117";
}
-.icon-github:before {
+.icon-flip:before {
content: "\f118";
}
-.icon-hidden:before {
+.icon-github:before {
content: "\f119";
}
-.icon-info:before {
+.icon-hidden:before {
content: "\f11a";
}
-.icon-isolate:before {
+.icon-info:before {
content: "\f11b";
}
-.icon-light_mode:before {
+.icon-isolate:before {
content: "\f11c";
}
-.icon-materials:before {
+.icon-light_mode:before {
content: "\f11d";
}
-.icon-measure_angle:before {
+.icon-materials:before {
content: "\f11e";
}
-.icon-measure_distance_parallel:before {
+.icon-measure_angle:before {
content: "\f11f";
}
-.icon-measure_distance:before {
+.icon-measure_distance_parallel:before {
content: "\f120";
}
-.icon-measure:before {
+.icon-measure_distance:before {
content: "\f121";
}
-.icon-meshes:before {
+.icon-measure:before {
content: "\f122";
}
-.icon-missing_files:before {
+.icon-meshes:before {
content: "\f123";
}
-.icon-model:before {
+.icon-missing_files:before {
content: "\f124";
}
-.icon-open_url:before {
+.icon-model:before {
content: "\f125";
}
-.icon-open:before {
+.icon-open_url:before {
content: "\f126";
}
-.icon-print3d:before {
+.icon-open:before {
content: "\f127";
}
-.icon-settings:before {
+.icon-print3d:before {
content: "\f128";
}
-.icon-share:before {
+.icon-settings:before {
content: "\f129";
}
-.icon-snapshot:before {
+.icon-share:before {
content: "\f12a";
}
-.icon-tree_mesh:before {
+.icon-snapshot:before {
content: "\f12b";
}
-.icon-tree_view:before {
+.icon-tree_mesh:before {
content: "\f12c";
}
-.icon-twitter:before {
+.icon-tree_view:before {
content: "\f12d";
}
-.icon-up_y:before {
+.icon-twitter:before {
content: "\f12e";
}
-.icon-up_z:before {
+.icon-up_y:before {
content: "\f12f";
}
-.icon-visible:before {
+.icon-up_z:before {
content: "\f130";
}
-.icon-warning:before {
+.icon-visible:before {
content: "\f131";
}
+.icon-warning:before {
+ content: "\f132";
+}