9 Commits

Author SHA1 Message Date
omrips 6fbc2cc36a Add files via upload
//New in 1.12 => improve auto_zoom algorithm by Michal Jirku (https://wejn.org/2020/12/cracking-the-threejs-object-fitting-nut/)
//New in 1.12 => "dispose" function
//New in 1.12 => fixed memory leak on "clean" function (thanks to Anthony https://github.com/antho1404)
//New in 1.12 => use 'fetch' instead for xhr when possible (thanks to Anthony https://github.com/antho1404)
//New in 1.12 => added get_vsb_blob (returns vsb file as binary)
//New in 1.12 => set viewstl to take all of the container (and not 5px margin)
//New in 1.12 => fixed bug in json_without_nulls function
2021-02-09 18:12:03 +02:00
omrips 8e88aec93f Add files via upload 2021-02-09 18:11:02 +02:00
omrips 843ece22e1 Merge pull request #10 from antho1404/patch-1
Switch to fetch to retrieve files
2021-02-03 16:21:06 +02:00
antho1404 733d981b81 download compatibility with fetch and xhr 2021-01-29 10:28:59 +07:00
Anthony e0143c9f59 Switch to fetch to retrieve files 2021-01-28 10:17:30 +07:00
omrips 649d10d8f9 on_mouse_click event
add 'click_type parameter'
2020-12-07 15:28:47 +02:00
omrips e4b97cb853 Add files via upload 2020-12-07 15:28:08 +02:00
omrips 58ebbf5aad Delete stl_viewer.js 2020-12-07 15:27:50 +02:00
omrips 4a72cbdd37 on_mouse_click event
add 'click_type' parameter
2020-12-07 15:27:13 +02:00
5 changed files with 214 additions and 57 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
//=========== Stl Viewer v1.11, by Omri Rips, Viewstl.com, November 2020 ; admin@viewstl.com ===========
importScripts("parser.min.js"),MSG_DATA=0,MSG_LOAD=1,MSG_ERROR=2,MSG_STL_LOADED=3,MSG_LOAD_IN_PROGRESS=4;var filename=null,local_file=null,load_from_blob_or_ab=null,x=0,y=0,z=0,model_id=-1,get_progress=!1;function isNumeric(a){return!isNaN(parseFloat(a))&&isFinite(a)}function send_error(a){postMessage({msg_type:MSG_ERROR,data:a})}function download_from_local(a){var e=new XMLHttpRequest;get_progress&&(e.onprogress=function(a){postMessage({msg_type:MSG_LOAD_IN_PROGRESS,id:model_id,loaded:a.loaded,total:a.total})}),e.onreadystatechange=function(a){4==e.readyState&&200==e.status&&after_file_load(e.response)},e.open("GET",a,!0),e.setRequestHeader("Content-type","application/x-www-form-urlencoded"),e.responseType="arraybuffer",e.send(null)}function after_file_load(a){var e;if(a){try{e=parse_3d_file(filename,a)}catch(a){e="Error parsing the file"}"string"!=typeof e?postMessage({msg_type:MSG_STL_LOADED,vertices:e.vertices,faces:e.faces,colors:e.colors}):send_error(e)}else send_error("no data")}function read_file(a){var e=new FileReader;e.onerror=function(a){var e="";switch(a.target.error.code){case a.target.error.NOT_FOUND_ERR:e="File not found";break;case a.target.error.NOT_READABLE_ERR:e="Can't read file - too large?";break;case a.target.error.ABORT_ERR:e="Read operation aborted";break;case a.target.error.SECURITY_ERR:e="File is locked";break;case a.target.error.ENCODING_ERR:e="File too large";break;default:e="Error reading file"}send_error(e)},e.onprogress=function(a){postMessage({msg_type:MSG_LOAD_IN_PROGRESS,id:model_id,loaded:a.loaded,total:a.total})},e.onload=function(a){after_file_load(a.target.result)},e.readAsArrayBuffer(a)}self.addEventListener("message",function(a){switch(a.data.msg_type){case MSG_DATA:if(!a.data.data){send_error("no data");break}if(!a.data.data.filename&&!a.data.data.local_file){send_error("no file");break}a.data.data.local_file?(filename=a.data.data.local_file.name?a.data.data.local_file.name:a.data.data.filename,local_file=a.data.data.local_file?a.data.data.local_file:null):a.data.data.filename&&(filename=a.data.data.filename),a.data.data.x&&isNumeric(a.data.data.x)&&(x=a.data.data.x),a.data.data.y&&isNumeric(a.data.data.y)&&(y=a.data.data.y),a.data.data.y&&isNumeric(a.data.data.z)&&(z=a.data.data.z),load_from_blob_or_ab=null,a.data.load_from_blob_or_ab&&(load_from_blob_or_ab=a.data.load_from_blob_or_ab),model_id=a.data.data.id?a.data.data.id:-1,get_progress=!!a.data.get_progress&&a.data.get_progress;break;case MSG_LOAD:load_from_blob_or_ab?load_from_blob_or_ab instanceof ArrayBuffer?after_file_load(load_from_blob_or_ab):read_file(load_from_blob_or_ab):local_file?read_file(local_file):filename&&download_from_local(filename);break;default:console.log("invalid msg: "+a.data.msg_type)}});
//=========== Stl Viewer v1.12, by Omri Rips, Viewstl.com, February 2021 ; admin@viewstl.com ===========
importScripts("parser.min.js"),MSG_DATA=0,MSG_LOAD=1,MSG_ERROR=2,MSG_STL_LOADED=3,MSG_LOAD_IN_PROGRESS=4;var filename=null,local_file=null,load_from_blob_or_ab=null,x=0,y=0,z=0,model_id=-1,get_progress=!1;function isNumeric(a){return!isNaN(parseFloat(a))&&isFinite(a)}function send_error(a){postMessage({msg_type:MSG_ERROR,data:a})}function download_from_local(a){fetch?download_from_local_fetch(a):download_from_local_xhr(a)}function download_from_local_xhr(a){var e=new XMLHttpRequest;get_progress&&(e.onprogress=function(a){postMessage({msg_type:MSG_LOAD_IN_PROGRESS,id:model_id,loaded:a.loaded,total:a.total})}),e.onreadystatechange=function(a){4==e.readyState&&200==e.status&&after_file_load(e.response)},e.open("GET",a,!0),e.responseType="arraybuffer",e.send(null)}async function download_from_local_fetch(a){const e=await fetch(a),o=e.body.getReader(),r=Number(e.headers.get("content-length")),t=new Uint8Array(r);let l=0;for(;;){const{done:a,value:e}=await o.read();if(a)break;e&&(t.set(e,l),l+=e.length,get_progress&&postMessage({msg_type:MSG_LOAD_IN_PROGRESS,id:model_id,loaded:l,total:r}))}after_file_load(t.buffer)}function after_file_load(a){var e;if(a){try{e=parse_3d_file(filename,a)}catch(a){e="Error parsing the file"}"string"!=typeof e?postMessage({msg_type:MSG_STL_LOADED,vertices:e.vertices,faces:e.faces,colors:e.colors}):send_error(e)}else send_error("no data")}function read_file(a){var e=new FileReader;e.onerror=function(a){var e="";switch(a.target.error.code){case a.target.error.NOT_FOUND_ERR:e="File not found";break;case a.target.error.NOT_READABLE_ERR:e="Can't read file - too large?";break;case a.target.error.ABORT_ERR:e="Read operation aborted";break;case a.target.error.SECURITY_ERR:e="File is locked";break;case a.target.error.ENCODING_ERR:e="File too large";break;default:e="Error reading file"}send_error(e)},e.onprogress=function(a){postMessage({msg_type:MSG_LOAD_IN_PROGRESS,id:model_id,loaded:a.loaded,total:a.total})},e.onload=function(a){after_file_load(a.target.result)},e.readAsArrayBuffer(a)}self.addEventListener("message",function(a){switch(a.data.msg_type){case MSG_DATA:if(!a.data.data){send_error("no data");break}if(!a.data.data.filename&&!a.data.data.local_file){send_error("no file");break}a.data.data.local_file?(filename=a.data.data.local_file.name?a.data.data.local_file.name:a.data.data.filename,local_file=a.data.data.local_file?a.data.data.local_file:null):a.data.data.filename&&(filename=a.data.data.filename),a.data.data.x&&isNumeric(a.data.data.x)&&(x=a.data.data.x),a.data.data.y&&isNumeric(a.data.data.y)&&(y=a.data.data.y),a.data.data.y&&isNumeric(a.data.data.z)&&(z=a.data.data.z),load_from_blob_or_ab=null,a.data.load_from_blob_or_ab&&(load_from_blob_or_ab=a.data.load_from_blob_or_ab),model_id=a.data.data.id?a.data.data.id:-1,get_progress=!!a.data.get_progress&&a.data.get_progress;break;case MSG_LOAD:load_from_blob_or_ab?load_from_blob_or_ab instanceof ArrayBuffer?after_file_load(load_from_blob_or_ab):read_file(load_from_blob_or_ab):local_file?read_file(local_file):filename&&download_from_local(filename);break;default:console.log("invalid msg: "+a.data.msg_type)}});
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
File diff suppressed because one or more lines are too long
+39 -3
View File
@@ -1,4 +1,4 @@
//1.10
//1.12
//load STL file info geometry and returns it
importScripts("parser.min.js");
@@ -44,6 +44,7 @@ self.addEventListener("message", function(e)
model_id=e.data.data.id?e.data.data.id:-1;
get_progress=e.data.get_progress?e.data.get_progress:false;
break;
case MSG_LOAD:
@@ -74,13 +75,26 @@ self.addEventListener("message", function(e)
function isNumeric(n)
{
return !isNaN(parseFloat(n)) && isFinite(n);
}
}
function send_error(s)
{
postMessage({msg_type:MSG_ERROR, data:s});
}
function download_from_local(filename)
{
if (fetch)
{
download_from_local_fetch(filename);
}
else
{
download_from_local_xhr(filename);
}
}
function download_from_local_xhr(filename)
{
var xhr = new XMLHttpRequest();
@@ -108,12 +122,34 @@ function download_from_local(filename)
}
xhr.open("GET", filename, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.responseType = "arraybuffer";
xhr.send(null);
}
async function download_from_local_fetch(filename)
{
const response = await fetch(filename);
const reader = response.body.getReader();
const total = Number(response.headers.get('content-length'));
const chunksAll = new Uint8Array(total);
let position = 0
while (true)
{
const { done, value } = await reader.read()
if (done) break;
if (!value) continue;
chunksAll.set(value, position);
position += value.length;
if (get_progress)
{
postMessage({ msg_type: MSG_LOAD_IN_PROGRESS, id: model_id, loaded: position, total: total });
}
}
after_file_load(chunksAll.buffer)
}
function after_file_load(s)
{
var vf_data;
+170 -49
View File
@@ -1,5 +1,14 @@
//1.11
//1.12
//**********************************************************
//New in 1.12 => improve auto_zoom algorithm by Michal Jirku (https://wejn.org/2020/12/cracking-the-threejs-object-fitting-nut/)
//New in 1.12 => "dispose" function
//New in 1.12 => fixed memory leak on "clean" function (thanks to Anthony https://github.com/antho1404)
//New in 1.12 => use 'fetch' instead for xhr when possible (thanks to Anthony https://github.com/antho1404)
//New in 1.12 => added get_vsb_blob (returns vsb file as binary)
//New in 1.12 => set viewstl to take all of the container (and not 5px margin)
//New in 1.12 => fixed bug in json_without_nulls function
//New in 1.12 => cal vol/area bug
//New in 1.12 => remove edges where model is removed
//New in 1.11 => set grid
//New in 1.10 => revoke dataURLs
//New in 1.10 => fix issue with rotation at 0 angle
@@ -46,6 +55,7 @@ function StlViewer(parent_element_obj, options)
if (!_this.options) return def;
if (_this.options[opt_id]===false) return false;
return _this.options[opt_id]?_this.options[opt_id]:def;
}
@@ -89,6 +99,8 @@ function StlViewer(parent_element_obj, options)
this.zip_load_count=-1; //Zip files waiting to be loaded to memory (used when loading VSB)
this.send_no_model_click_event=false; //will trigger click event even if no model was clicked (just parent element was clicked)
this.grid=null; //draw grid over scene
this.killsign=false; //use by 'dispose', stl_viewer instqance will be unusable after setting this to true
this.set_on_model_mousedown = function (callback)
{
@@ -97,6 +109,7 @@ function StlViewer(parent_element_obj, options)
if (_this.onmousedown_callback)
{
_this.parent_element.addEventListener('mousedown', _this.onmousedown);
_this.parent_element.addEventListener('dblclick', _this.onmousedown);
_this.parent_element.addEventListener('touchstart', _this.onmousedown);
}
}
@@ -249,6 +262,7 @@ function StlViewer(parent_element_obj, options)
var blob_to_load=null;
if (_this.pre_loaded_ab_files) if (model.filename) if (_this.pre_loaded_ab_files[model.filename]) blob_to_load=_this.pre_loaded_ab_files[model.filename];
//console.log ('blob to load', blob_to_load, _this.pre_loaded_ab_files, _this.pre_loaded_ab_files[model.filename]);
model_worker.postMessage({msg_type:_this.MSG2WORKER_DATA, data:model, load_from_blob_or_ab:blob_to_load, get_progress:(_this.loading_progress_callback!=null)});
model_worker.postMessage({msg_type:_this.MSG2WORKER_LOAD});
@@ -306,6 +320,8 @@ function StlViewer(parent_element_obj, options)
var model=_this.models[_this.models_ref[model_id]];
if (!model) return;
_this.set_or_update_geo_edges (model, false);
delete _this.models[_this.models_ref[model_id]];
delete _this.models_ref[model_id];
delete _this.loaded_models_arr[model_id];
@@ -334,11 +350,36 @@ function StlViewer(parent_element_obj, options)
_this.zoom_done=true;
//var max_dim = Math.max(_this.maxx*2, _this.maxy*2, _this.maxz);
//_this.camera.position.set(_this.camera.position.x,_this.camera.position.y,_this.zoom>=0?_this.zoom:(max_dim*1.2*Math.max(1,_this.camera.aspect/2))); //-1 = auto zoom
var max_dim = Math.max(Math.abs(_this.maxx-_this.minx), Math.abs(_this.maxy-_this.miny), Math.abs(_this.maxz-_this.minz));
_this.camera.position.set(_this.camera.position.x,_this.camera.position.y,_this.zoom>=0?_this.zoom:max_dim*2); //-1 = auto zoom
//var max_dim = Math.max(Math.abs(_this.maxx-_this.minx), Math.abs(_this.maxy-_this.miny), Math.abs(_this.maxz-_this.minz));
var cameraZ=_this.zoom;
if (_this.zoom<0) cameraZ=_this.calc_z_for_auto_zoom(); //-1 = auto zoom
_this.camera.position.set(_this.camera.position.x,_this.camera.position.y,cameraZ);
// set the far plane of the camera so that it easily encompasses the whole object
const minZ = _this.minz;
const cameraToFarEdge = ( minZ < 0 ) ? -minZ + cameraZ : cameraZ - minZ;
_this.camera.far = cameraToFarEdge * 3;
_this.camera.updateProjectionMatrix();
}
this.calc_z_for_auto_zoom=function (offset)
{
offset = offset || 1.01;
const boundingBox = new THREE.Box3(new THREE.Vector3( _this.minx, _this.miny, _this.minz ), new THREE.Vector3( _this.maxx, _this.maxy, _this.maxz ));
var size = new THREE.Vector3();
boundingBox.getSize(size);
const fov = _this.camera.fov * ( Math.PI / 180 );
const fovh = 2*Math.atan(Math.tan(fov/2) * _this.camera.aspect);
let dx = size.z / 2 + Math.abs( size.x / 2 / Math.tan( fovh / 2 ) );
let dy = size.z / 2 + Math.abs( size.y / 2 / Math.tan( fov / 2 ) );
let cameraZ = Math.max(dx, dy);
cameraZ *= offset;
return cameraZ;
}
//position, up and target vectors (each 3 coors vector) described camera's position
this.get_camera_state=function()
@@ -710,32 +751,40 @@ function StlViewer(parent_element_obj, options)
event.stopPropagation();
event.preventDefault();
//reset click_type: 1=left click, 3=right click, 11=double click, 20=touch
var click_type=event.which;
switch (event.type)
{
case 'touchstart':
click_type=20;
var touch = event.touches[0] || event.changedTouches[0];
_this.mouse.x = ( (touch.pageX-_this.parent_element.offsetLeft) / _this.parent_element.clientWidth ) * 2 - 1;
_this.mouse.y = - ( (touch.pageY-_this.parent_element.offsetTop) / _this.parent_element.clientHeight ) * 2 + 1;
break;
case 'dblclick': //double-click
click_type=11;
default: //click
_this.mouse.x = ( (event.clientX-_this.parent_element.offsetLeft) / _this.parent_element.clientWidth ) * 2 - 1;
_this.mouse.y = - ( (event.clientY-_this.parent_element.offsetTop) / _this.parent_element.clientHeight ) * 2 + 1;
}
_this.raycaster.setFromCamera( _this.mouse, _this.camera );
var intersects = _this.raycaster.intersectObjects( _this.scene.children );
if (intersects.length>0)
{
if (intersects[0].object.model_id===undefined) return;
if (_this.onmousedown_callback)
{
_this.onmousedown_callback(intersects[0].object.model_id, event, intersects[0].distance);
_this.onmousedown_callback(intersects[0].object.model_id, event, intersects[0].distance, click_type);
}
}
else if (_this.send_no_model_click_event)
_this.onmousedown_callback(null, event, 0);
_this.onmousedown_callback(null, event, 0, click_type);
}
//will return if value is empty (null/undefined etc.) and not zero (which is valid)
@@ -1297,11 +1346,12 @@ function StlViewer(parent_element_obj, options)
this.json_without_nulls=function(arr)
{
return JSON.stringify(arr).split(",null").join("");
return JSON.stringify(arr).split(",null").join("").split("null,").join("");
}
this.download_vsb = function(filename)
this.get_vsb_blob = function()
{
//makes vsb and returns it as a blob
var zip=null;
try
{
@@ -1323,32 +1373,33 @@ function StlViewer(parent_element_obj, options)
zip.file(curr_filename, vsb.files[key].bin);
});
zip.generateAsync({type:"blob"})
.then(function(content)
{
var blob = new Blob([content], {type: "application/zip"});
var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
var download_name=filename?filename:"1";
var p=download_name.toLowerCase().indexOf('.vsb');
if (p>=0) download_name=download_name.substring( 0, p );
if (download_name.length<1) download_name='1';
if (window.navigator.msSaveOrOpenBlob)
{
//only for IE
window.navigator.msSaveBlob(blob, download_name+'.vsb');
return;
}
return zip.generateAsync({type:"blob"});
}
this.download_vsb = function(filename)
{
_this.get_vsb_blob(filename).then(function(content)
{
var blob = new Blob([content], {type: "application/zip"});
link.download = download_name+'.vsb';
link.click();
URL.revokeObjectURL(link.href);
});
return;
var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
var download_name=filename?filename:"1";
var p=download_name.toLowerCase().indexOf('.vsb');
if (p>=0) download_name=download_name.substring( 0, p );
if (download_name.length<1) download_name='1';
if (window.navigator.msSaveOrOpenBlob)
{
//only for IE
window.navigator.msSaveBlob(blob, download_name+'.vsb');
return;
}
link.download = download_name+'.vsb';
link.click();
URL.revokeObjectURL(link.href);
});
}
this.load_vsb = function(filename)
@@ -1529,28 +1580,32 @@ function StlViewer(parent_element_obj, options)
this.do_resize = function()
{
if (!_this.parent_element) return;
var r=_this.parent_element.getBoundingClientRect();
//var r=_this.parent_element.children[0].getBoundingClientRect();
var rsize_width=r.width;
var rsize_height=r.height;
_this.camera.aspect = rsize_width / rsize_height;
_this.camera.updateProjectionMatrix();
_this.renderer.setSize(rsize_width-5, rsize_height-5);
//_this.renderer.setSize(rsize_width-5, rsize_height-5);
_this.renderer.setSize(rsize_width, rsize_height);
}
this.animation=new Array();
this.animate = function()
{
if (_this.killsign) return;
Object.keys(_this.animation).forEach(function(key)
{
if (!(_this.models_ref[key]===undefined))
_this.do_model_animation(_this.models[_this.models_ref[key]]);
});
requestAnimationFrame(_this.animate);
_this.renderer.render(_this.scene, _this.camera);
//console.log(_this.camera.position);
requestAnimationFrame(_this.animate);
if (_this.renderer)
_this.renderer.render(_this.scene, _this.camera);
if (_this.controls)
_this.controls.update();
@@ -2000,25 +2055,41 @@ function StlViewer(parent_element_obj, options)
this.clean = function()
{
_this.models=null;_this.models=[];
_this.models_count=0;
_this.models_ref=null;_this.models_ref=[];
_this.max_model_id=0;
_this.load_status=null;_this.load_status=[];
_this.load_session=0;
_this.loaded_models_arr=null;_this.loaded_models_arr=[];
_this.animation=null;_this.animation=[];
_this.models_to_add=null;_this.models_to_add=[];
_this.options.models=null;
if (!_this.scene) return;
var scene=_this.scene;
i=scene.children.length;
while (i--)
{
if (scene.children[i].type==='Mesh')
{
scene.children[i].geometry.dispose();
scene.children[i].material.dispose();
scene.remove(scene.children[i]);
}
}
_this.camera.position.set(_this.camerax,_this.cameray,_this.cameraz);
//remove edges for each model
Object.keys(_this.models_ref).forEach(function(key)
{
_this.set_or_update_geo_edges (_this.models[_this.models_ref[key]], false);
});
_this.models=new Array();
_this.models_count=0;
_this.models_ref=new Array();
_this.max_model_id=0;
_this.load_status=new Array();
_this.load_session=0;
_this.loaded_models_arr=new Array();
_this.animation=new Array();
//_this.camera.position.set(_this.camerax,_this.cameray,_this.cameraz);
_this.renderer.renderLists.dispose();
}
this.reset_parent_element=function(parent_element_obj)
@@ -2071,6 +2142,56 @@ function StlViewer(parent_element_obj, options)
_this.init();
}
this.dispose = function()
{
//clean object's references (and let brower's GC do it work)
_this.clean();
_this.killsign=true; //not to render anymore
if (_this.renderer) //one last render (to clean it all)
_this.renderer.render(_this.scene, _this.camera);
if (_this.controls)
_this.controls.update();
_this.animate=null;
_this.animation=null;
_this.error=null;
_this.options=null;
_this.parent_element=null;
_this.models_to_add=null;
_this.models=null;
_this.models_ref=null;
_this.model_loaded_callback=null;
_this.all_loaded_callback=null;
_this.load_error_callback=null;
_this.loading_progress_callback=null;
_this.load_status=null;
_this.loaded_models_arr=null;
_this.onmousedown_callback=null;
_this.camera_state=null;
_this.ready_callback=null;
_this.on_model_drop=null;
_this.pre_loaded_ab_files=null;
_this.pre_loaded_vsj=null;
_this.grid=null;
_this.WORLD_X_VECTOR=null;
_this.WORLD_Y_VECTOR=null;
_this.WORLD_Z_VECTOR=null;
_this.edges_material=null;
_this.raycaster=null;
_this.mouse =null;
_this.renderer = null;
_this.scene = null;
_this.camera = null;
_this.ambientLight = null;
_this.directionalLight = null;
_this.pointLight = null;
_this.controls = null;
}
//constructor
_this.set_options();