/**
* @file Set of functions to mainpulate files
*/
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
/**
* Download on the local disk an object as .json
*
* @param {object} exportObj - object to download
* @param {string} exportName - name of file
*/
export function downloadObjectAsJson(exportObj, exportName) {
const dataStr =
'data:text/json;charset=utf-8,' +
encodeURIComponent(JSON.stringify(exportObj));
const downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute('href', dataStr);
downloadAnchorNode.setAttribute('download', exportName + '.json');
document.body.appendChild(downloadAnchorNode); // Required for firefox
downloadAnchorNode.click();
downloadAnchorNode.remove();
}
/**
* Request a json file on a distant server
*
* @param {string} url - on the distant server
* @returns {Promise} - promise resolving when .json loaded and pass it as first param
*/
export function loadJSON(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => {
if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
}
};
xhr.onerror = reject;
xhr.send();
});
}
/**
* Request a text file on a distant server
*
* @param {string} url - on the distant server
* @returns {Promise} - promise resolving when file loaded and pass it as first param
*/
export function loadTextFile(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => {
if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText);
}
};
xhr.onerror = reject;
xhr.send();
});
}
/**
* Load multiples .json files
*
* @param {string[]} urlArray - path of .json files to loaded
* @returns {Promise} - promise reolving when .json files loaded, each .json file can be access by the filename
* @example
* loadMultipleJSON(["./some_folder/filename1.json","./another_folder/filename2.json"])
* .then((configs)=>{
* const contentFilename1 = configs["filename1"]
* const contentFilename2 = configs["filename2"]
* })
*/
export function loadMultipleJSON(urlArray) {
return new Promise((resolve, reject) => {
const promises = [];
const result = {};
urlArray.forEach((url) => {
promises.push(
loadJSON(url).then((jsonResult) => {
const key = computeFileNameFromPath(url);
if (result[key]) throw new Error('conflict same key');
result[key] = jsonResult;
})
);
});
Promise.all(promises)
.then(() => {
resolve(result);
})
.catch(reject);
});
}
/**
*
* @param {string} path - path of file
* @returns {string} - name of file
* @example
* console.log(computeFilename("./some_folder/another_folder/filename.whatever"))// log filename
*/
export function computeFileNameFromPath(path) {
const indexLastSlash = path.lastIndexOf('/');
const indexLastPoint = path.lastIndexOf('.');
return path.slice(indexLastSlash + 1, indexLastPoint);
}
/**
* @callback FileReaderCallback
* @param {ProgressEvent<FileReader>} event - file reader event
*/
/**
* To be used with an input of type file
*
* @param {object} e - input of type file argument when 'change'
* @param {FileReaderCallback | null} onLoad - callback when file loaded
*/
export function readSingleFileAsText(e, onLoad) {
try {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = onLoad;
reader.readAsText(file);
}
} catch (e) {
throw new Error(e);
}
}
/**
* To be used with an input of type file
*
* @param {object} e input of type file argument when 'change'
* @param {FileReaderCallback} onLoad - callback when file loaded
*/
export function readSingleFileAsDataUrl(e, onLoad) {
try {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = onLoad;
reader.readAsDataURL(file);
}
} catch (e) {
throw new Error(e);
}
}
/**
* Download an image on the local disk
*
* @param {string} url - url of the image to download
* @param {string} filename - name of the file on disk
*/
export function downloadImageOnDisk(url, filename) {
const imgResult = document.createElement('img');
imgResult.src = url;
const link = document.createElement('a');
link.href = imgResult.src;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
/**
* change callback of an input file reading gltf
*
* @param {object} e input of type file argument when 'change'
* @returns {Promise} promise resolving with the gltf loaded
*/
export function readFileAsGltf(e) {
return new Promise((resolve) => {
const fileReader = new FileReader();
const loader = new GLTFLoader();
const file = e.target.files[0];
fileReader.readAsArrayBuffer(file);
fileReader.onload = (result) => {
loader.parse(
result.target.result,
'',
function (gltf) {
resolve(gltf);
},
false
);
};
});
}