Spaces:
Running
Running
| // Common Javascript functions used by the examples | |
| function convertTypedArray(src, type) { | |
| var buffer = new ArrayBuffer(src.byteLength); | |
| var baseView = new src.constructor(buffer).set(src); | |
| return new type(buffer); | |
| } | |
| var printTextarea = (function() { | |
| var element = document.getElementById('output'); | |
| if (element) element.alue = ''; // clear browser cache | |
| return function(text) { | |
| if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); | |
| console.log(text); | |
| if (element) { | |
| element.value += text + "\n"; | |
| element.scrollTop = element.scrollHeight; // focus on bottom | |
| } | |
| }; | |
| })(); | |
| async function clearCache() { | |
| if (confirm('Are you sure you want to clear the cache?\nAll the models will be downloaded again.')) { | |
| indexedDB.deleteDatabase(dbName); | |
| } | |
| } | |
| // fetch a remote file from remote URL using the Fetch API | |
| async function fetchRemote(url, cbProgress, cbPrint) { | |
| cbPrint('fetchRemote: downloading with fetch()...'); | |
| const response = await fetch( | |
| url, | |
| { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/octet-stream', | |
| }, | |
| } | |
| ); | |
| if (!response.ok) { | |
| cbPrint('fetchRemote: failed to fetch ' + url); | |
| return; | |
| } | |
| const contentLength = response.headers.get('content-length'); | |
| const total = parseInt(contentLength, 10); | |
| const reader = response.body.getReader(); | |
| var chunks = []; | |
| var receivedLength = 0; | |
| var progressLast = -1; | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) { | |
| break; | |
| } | |
| chunks.push(value); | |
| receivedLength += value.length; | |
| if (contentLength) { | |
| cbProgress(receivedLength/total); | |
| var progressCur = Math.round((receivedLength / total) * 10); | |
| if (progressCur != progressLast) { | |
| cbPrint('fetchRemote: fetching ' + 10*progressCur + '% ...'); | |
| progressLast = progressCur; | |
| } | |
| } | |
| } | |
| var position = 0; | |
| var chunksAll = new Uint8Array(receivedLength); | |
| for (var chunk of chunks) { | |
| chunksAll.set(chunk, position); | |
| position += chunk.length; | |
| } | |
| return chunksAll; | |
| } | |
| // load remote data | |
| // - check if the data is already in the IndexedDB | |
| // - if not, fetch it from the remote URL and store it in the IndexedDB | |
| function loadRemote(url, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) { | |
| // query the storage quota and print it | |
| navigator.storage.estimate().then(function (estimate) { | |
| cbPrint('loadRemote: storage quota: ' + estimate.quota + ' bytes'); | |
| cbPrint('loadRemote: storage usage: ' + estimate.usage + ' bytes'); | |
| }); | |
| // check if the data is already in the IndexedDB | |
| var rq = indexedDB.open(dbName, dbVersion); | |
| rq.onupgradeneeded = function (event) { | |
| var db = event.target.result; | |
| if (db.version == 1) { | |
| var os = db.createObjectStore('models', { autoIncrement: false }); | |
| cbPrint('loadRemote: created IndexedDB ' + db.name + ' version ' + db.version); | |
| } else { | |
| // clear the database | |
| var os = event.currentTarget.transaction.objectStore('models'); | |
| os.clear(); | |
| cbPrint('loadRemote: cleared IndexedDB ' + db.name + ' version ' + db.version); | |
| } | |
| }; | |
| rq.onsuccess = function (event) { | |
| var db = event.target.result; | |
| var tx = db.transaction(['models'], 'readonly'); | |
| var os = tx.objectStore('models'); | |
| var rq = os.get(url); | |
| rq.onsuccess = function (event) { | |
| if (rq.result) { | |
| cbPrint('loadRemote: "' + url + '" is already in the IndexedDB'); | |
| cbReady(dst, rq.result); | |
| } else { | |
| // data is not in the IndexedDB | |
| cbPrint('loadRemote: "' + url + '" is not in the IndexedDB'); | |
| // alert and ask the user to confirm | |
| if (!confirm( | |
| 'You are about to download ' + size_mb + ' MB of data.\n' + | |
| 'The model data will be cached in the browser for future use.\n\n' + | |
| 'Press OK to continue.')) { | |
| cbCancel(); | |
| return; | |
| } | |
| fetchRemote(url, cbProgress, cbPrint).then(function (data) { | |
| if (data) { | |
| // store the data in the IndexedDB | |
| var rq = indexedDB.open(dbName, dbVersion); | |
| rq.onsuccess = function (event) { | |
| var db = event.target.result; | |
| var tx = db.transaction(['models'], 'readwrite'); | |
| var os = tx.objectStore('models'); | |
| var rq = os.put(data, url); | |
| rq.onsuccess = function (event) { | |
| cbPrint('loadRemote: "' + url + '" stored in the IndexedDB'); | |
| cbReady(dst, data); | |
| }; | |
| rq.onerror = function (event) { | |
| cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB'); | |
| cbCancel(); | |
| }; | |
| }; | |
| } | |
| }); | |
| } | |
| }; | |
| rq.onerror = function (event) { | |
| cbPrint('loadRemote: failed to get data from the IndexedDB'); | |
| cbCancel(); | |
| }; | |
| }; | |
| rq.onerror = function (event) { | |
| cbPrint('loadRemote: failed to open IndexedDB'); | |
| cbCancel(); | |
| }; | |
| rq.onblocked = function (event) { | |
| cbPrint('loadRemote: failed to open IndexedDB: blocked'); | |
| cbCancel(); | |
| }; | |
| rq.onabort = function (event) { | |
| cbPrint('loadRemote: failed to open IndexedDB: abort'); | |
| }; | |
| } | |