I have a large amount of textures and models to load into my project. I am trying to show a progress bars while everything is loading. I think the LoadingManager
as @2pha points out, the below is pointless as THREE already implements a loading Manager - the below will remain for posterity, but have a look at this:
https://threejs.org/docs/?q=loading#api/loaders/managers/LoadingManager
Easy-peasy:
var progress = document.createElement('div');
var progressBar = document.createElement('div');
progress.appendChild(progressBar);
document.body.appendChild(progress);
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
progressBar.style.width = (loaded / total * 100) + '%';
};
function addRandomPlaceHoldItImage(){
var r = Math.round(Math.random() * 4000);
new THREE.ImageLoader(manager).load('http://placehold.it/' + r + 'x' + r);
}
for(var i = 0; i < 10; i++) addRandomPlaceHoldItImage();
div {
width: 200px;
height: 20px;
background: #000;
border: 2px solid #000;
}
div > div {
width: 200px;
height: 20px;
background: red;
border: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r74/three.min.js"></script>
Something like the below should do your trick - mind that I have just quickly tested it and there is probably a couple of improvements to make (including using the progress
callback in THREE js). I haven't fully refined it either, but it gives you a general implementation of how to do this. I also haven't implemented an error handler, etc... Those are things that take a bit longer to make, but you get the general idea.
You add new types of loaders (that conform to the type + Loader
in THREE) and their sources, then initiating the load by simply calling load
.
Hope it helps.
(I also made a random function to get some random images from placehold.it
since using the same results over and over means that caching kills the server.)
function LoaderProgress(callback){
this.length = -1;
this.complete = 0;
this.domElement = document.createElement('div');
this.progress = document.createElement('div');
this.domElement.appendChild(this.progress);
this.domElement.className = 'loader-progress-wrapper';
this.progress.className = 'loader-progress-progress';
this.progress.style.width = '0%';
this.callback = callback || function(){};
}
LoaderProgress.prototype.add = function(type, src){
var result = this[++this.length] = {
loader: new THREE[type + 'Loader'],
complete: false,
source: src
};
return result;
}
LoaderProgress.prototype.load = function(){
this.complete = 0;
for(var i = 0; i < this.length; i++){
var current = this[i];
if(!current.complete){
current.loader.load(this[i].source, function(result){
current.complete = result;
this.complete++;
this.update();
}.bind(this));
}
}
return this;
}
LoaderProgress.prototype.update = function(a){
var progress = this.complete / this.length;
this.progress.style.width = (progress * 100) + '%';
if(progress === 1) this.callback(this);
console.log(progress);
return progress;
}
var loader = new LoaderProgress(function(){
// Execute code that needfs the loaded elements here
alert('All are loaded');
});
document.body.appendChild(loader.domElement);
function addRandomPlaceHoldItImage(){
var r = Math.round(Math.random() * 4000);
loader.add('Image', 'http://placehold.it/' + r + 'x' + r);
}
for(var i = 0; i < 10; i++)
addRandomPlaceHoldItImage();
loader.load();
.loader-progress-wrapper {
width: 200px;
height: 20px;
background: #000;
border: 2px solid #000;
}
.loader-progress-progress {
width: 200px;
height: 20px;
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r74/three.min.js"></script>
Docs: http://threejs.org/docs/#Reference/Loaders/TextureLoader
Example: http://threejs.org/examples/#webgl_loader_obj
Code:
var sphereMaterial = new THREE.MeshBasicMaterial();
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var loader = new THREE.TextureLoader();
var texture = loader.load("___4MB_IMAGE.JPG___", undefined, onProgress);
sphereMaterial.map = texture;
It solves a similar problem I had - 4MB texture that takes some time to load over the wire...