three
Version:
JavaScript 3D library
298 lines (164 loc) • 5.66 kB
JavaScript
import { Cache } from './Cache.js';
import { Loader } from './Loader.js';
const loading = {};
class FileLoader extends Loader {
constructor( manager ) {
super( manager );
}
load( url, onLoad, onProgress, onError ) {
if ( url === undefined ) url = '';
if ( this.path !== undefined ) url = this.path + url;
url = this.manager.resolveURL( url );
const scope = this;
const cached = Cache.get( url );
if ( cached !== undefined ) {
scope.manager.itemStart( url );
setTimeout( function () {
if ( onLoad ) onLoad( cached );
scope.manager.itemEnd( url );
}, 0 );
return cached;
}
// Check if request is duplicate
if ( loading[ url ] !== undefined ) {
loading[ url ].push( {
onLoad: onLoad,
onProgress: onProgress,
onError: onError
} );
return;
}
// Check for data: URI
const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
const dataUriRegexResult = url.match( dataUriRegex );
let request;
// Safari can not handle Data URIs through XMLHttpRequest so process manually
if ( dataUriRegexResult ) {
const mimeType = dataUriRegexResult[ 1 ];
const isBase64 = !! dataUriRegexResult[ 2 ];
let data = dataUriRegexResult[ 3 ];
data = decodeURIComponent( data );
if ( isBase64 ) data = atob( data );
try {
let response;
const responseType = ( this.responseType || '' ).toLowerCase();
switch ( responseType ) {
case 'arraybuffer':
case 'blob':
const view = new Uint8Array( data.length );
for ( let i = 0; i < data.length; i ++ ) {
view[ i ] = data.charCodeAt( i );
}
if ( responseType === 'blob' ) {
response = new Blob( [ view.buffer ], { type: mimeType } );
} else {
response = view.buffer;
}
break;
case 'document':
const parser = new DOMParser();
response = parser.parseFromString( data, mimeType );
break;
case 'json':
response = JSON.parse( data );
break;
default: // 'text' or other
response = data;
break;
}
// Wait for next browser tick like standard XMLHttpRequest event dispatching does
setTimeout( function () {
if ( onLoad ) onLoad( response );
scope.manager.itemEnd( url );
}, 0 );
} catch ( error ) {
// Wait for next browser tick like standard XMLHttpRequest event dispatching does
setTimeout( function () {
if ( onError ) onError( error );
scope.manager.itemError( url );
scope.manager.itemEnd( url );
}, 0 );
}
} else {
// Initialise array for duplicate requests
loading[ url ] = [];
loading[ url ].push( {
onLoad: onLoad,
onProgress: onProgress,
onError: onError
} );
request = new XMLHttpRequest();
request.open( 'GET', url, true );
request.addEventListener( 'load', function ( event ) {
const response = this.response;
const callbacks = loading[ url ];
delete loading[ url ];
if ( this.status === 200 || this.status === 0 ) {
// Some browsers return HTTP Status 0 when using non-http protocol
// e.g. 'file://' or 'data://'. Handle as success.
if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
// Add to cache only on HTTP success, so that we do not cache
// error response bodies as proper responses to requests.
Cache.add( url, response );
for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
const callback = callbacks[ i ];
if ( callback.onLoad ) callback.onLoad( response );
}
scope.manager.itemEnd( url );
} else {
for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
const callback = callbacks[ i ];
if ( callback.onError ) callback.onError( event );
}
scope.manager.itemError( url );
scope.manager.itemEnd( url );
}
}, false );
request.addEventListener( 'progress', function ( event ) {
const callbacks = loading[ url ];
for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
const callback = callbacks[ i ];
if ( callback.onProgress ) callback.onProgress( event );
}
}, false );
request.addEventListener( 'error', function ( event ) {
const callbacks = loading[ url ];
delete loading[ url ];
for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
const callback = callbacks[ i ];
if ( callback.onError ) callback.onError( event );
}
scope.manager.itemError( url );
scope.manager.itemEnd( url );
}, false );
request.addEventListener( 'abort', function ( event ) {
const callbacks = loading[ url ];
delete loading[ url ];
for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
const callback = callbacks[ i ];
if ( callback.onError ) callback.onError( event );
}
scope.manager.itemError( url );
scope.manager.itemEnd( url );
}, false );
if ( this.responseType !== undefined ) request.responseType = this.responseType;
if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
for ( const header in this.requestHeader ) {
request.setRequestHeader( header, this.requestHeader[ header ] );
}
request.send( null );
}
scope.manager.itemStart( url );
return request;
}
setResponseType( value ) {
this.responseType = value;
return this;
}
setMimeType( value ) {
this.mimeType = value;
return this;
}
}
export { FileLoader };