You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

asset-manager.js 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /*!
  2. * An Asset Manager for AR
  3. * @version 1.0.0
  4. * @author Alexandre Martins (https://encantar.dev)
  5. * @license LGPL-3.0-or-later
  6. */
  7. /**
  8. * The Asset Manager is used to preload resources (models, textures, etc.)
  9. * You'll typically preload resources before starting the AR session
  10. */
  11. class AssetManager
  12. {
  13. /**
  14. * Get an object URL corresponding to a preloaded asset
  15. * @param {string} filename
  16. * @returns {string}
  17. * @throws Throws an error if the asset has not been successfully preloaded
  18. */
  19. url(filename)
  20. {
  21. return this._get(filename).url;
  22. }
  23. /**
  24. * Get a File corresponding to a preloaded asset
  25. * @param {string} filename
  26. * @returns {File}
  27. * @throws Throws an error if the asset has not been successfully preloaded
  28. */
  29. file(filename)
  30. {
  31. return this._get(filename).file;
  32. }
  33. /**
  34. * Check if an asset has been preloaded successfully
  35. * @param {string} filename
  36. * @returns {boolean}
  37. */
  38. has(filename)
  39. {
  40. return this._assetMap.has(filename);
  41. }
  42. /**
  43. * Preload one or more assets
  44. * @param {string|string[]} url URL(s) of the asset(s)
  45. * @param {object} [options]
  46. * @param {number} [options.timeout] timeout, in seconds
  47. * @returns {Promise<void>}
  48. */
  49. preload(url, options = {})
  50. {
  51. if(Array.isArray(url))
  52. return Promise.all(url.map(url => this.preload(url, options)));
  53. if(typeof url != 'string')
  54. return Promise.reject(new TypeError());
  55. const filename = url.substring(1 + url.lastIndexOf('/'));
  56. if(this._assetMap.has(filename))
  57. return Promise.resolve();
  58. return new Promise((resolve, reject) => {
  59. const seconds = options.timeout !== undefined ? options.timeout : Infinity;
  60. const timeoutFn = () => reject(new Error(`Can't preload assets: slow connection! Try refreshing the page.`));
  61. const timeoutId = isFinite(seconds) ? setTimeout(timeoutFn, seconds * 1000) : undefined;
  62. fetch(url)
  63. .then(response => {
  64. if(!response.ok)
  65. throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  66. return response.blob();
  67. })
  68. .then(blob => {
  69. const file = new File([ blob ], filename, { type: blob.type });
  70. const url = URL.createObjectURL(file);
  71. const asset = { file, url };
  72. this._assetMap.set(filename, asset);
  73. })
  74. .catch(error => {
  75. console.warn(`Can't preload asset "${filename}"! ${error.message} (${url})`);
  76. })
  77. .finally(() => {
  78. clearTimeout(timeoutId);
  79. resolve();
  80. });
  81. });
  82. }
  83. /**
  84. * Get a preloaded asset
  85. * @param {string} filename
  86. * @returns {object}
  87. * @throws {Error}
  88. * @internal
  89. */
  90. _get(filename)
  91. {
  92. const asset = this._assetMap.get(filename);
  93. if(!asset)
  94. throw new Error(`Asset "${filename}" has not been preloaded!`);
  95. return asset;
  96. }
  97. /**
  98. * Constructor
  99. */
  100. constructor()
  101. {
  102. this._assetMap = new Map();
  103. }
  104. }