prophetk-3d-viewer
Version:
A Three.js r128 based GLB/GLTF model viewer for WeChat Mini Program and Web.
132 lines (114 loc) • 4.03 kB
JavaScript
class WebPlatformAdapter {
constructor(options = {}) {
this.window = options.window || (typeof window !== 'undefined' ? window : null);
this.document = options.document || (typeof document !== 'undefined' ? document : null);
this._fileCache = new Map();
}
getWindowInfo() {
const win = this.window || {};
return {
pixelRatio: win.devicePixelRatio || 1,
windowWidth: win.innerWidth || 300,
windowHeight: win.innerHeight || 150,
};
}
getPixelRatio() {
return this.getWindowInfo().pixelRatio;
}
getContext(canvas, type) {
return canvas.getContext(type);
}
requestAnimationFrame(canvas, callback) {
const raf = this.window && this.window.requestAnimationFrame;
return raf ? raf.call(this.window, callback) : setTimeout(callback, 16);
}
cancelAnimationFrame(canvas, id) {
const caf = this.window && this.window.cancelAnimationFrame;
if (caf) caf.call(this.window, id);
else clearTimeout(id);
}
createImage() {
const img = new Image();
img.crossOrigin = 'anonymous';
return img;
}
createCanvas(width, height) {
const canvas = this.document.createElement('canvas');
canvas.width = width;
canvas.height = height;
return canvas;
}
requestJson(url) {
return fetch(url, {
cache: 'no-store',
headers: {
'Cache-Control': 'no-cache',
Pragma: 'no-cache',
},
}).then((res) => {
if (!res.ok) throw new Error('Request failed: ' + res.status);
return res.json();
});
}
fetchFile(sourceUrl, options = {}) {
const shouldCache = options.shouldCache !== false;
const url = options.url || sourceUrl;
const cacheKey = options.cacheKey || sourceUrl;
if (shouldCache && this._fileCache.has(cacheKey)) {
const entry = this._fileCache.get(cacheKey);
if (!entry.objectUrl) entry.objectUrl = URL.createObjectURL(entry.blob);
return Promise.resolve(entry.objectUrl);
}
return fetch(url, { cache: shouldCache ? 'default' : 'no-store' })
.then((res) => {
if (!res.ok) throw new Error('Download failed: ' + res.status);
return res.blob();
})
.then((blob) => {
const objectUrl = URL.createObjectURL(blob);
if (shouldCache) {
const old = this._fileCache.get(cacheKey);
if (old) URL.revokeObjectURL(old.objectUrl);
this._fileCache.set(cacheKey, { objectUrl, blob });
}
return objectUrl;
});
}
fetchArrayBuffer(sourceUrl, options = {}) {
const shouldCache = options.shouldCache !== false;
const url = options.url || sourceUrl;
const cacheKey = options.cacheKey || sourceUrl;
if (shouldCache && this._fileCache.has(cacheKey)) {
return this._fileCache.get(cacheKey).blob.arrayBuffer();
}
return fetch(url, { cache: shouldCache ? 'default' : 'no-store' })
.then((res) => {
if (!res.ok) throw new Error('Download failed: ' + res.status);
return res.blob();
})
.then((blob) => {
if (shouldCache) this._fileCache.set(cacheKey, { objectUrl: '', blob });
return blob.arrayBuffer();
});
}
readFileBase64(objectUrl) {
const entry = Array.from(this._fileCache.values()).find((item) => item.objectUrl === objectUrl);
if (!entry) return Promise.reject(new Error('file is not cached as blob'));
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
const result = String(reader.result || '');
resolve(result.split(',')[1] || '');
};
reader.onerror = reject;
reader.readAsDataURL(entry.blob);
});
}
dispose() {
this._fileCache.forEach((entry) => {
if (entry.objectUrl) URL.revokeObjectURL(entry.objectUrl);
});
this._fileCache.clear();
}
}
module.exports = WebPlatformAdapter;