Hello,
very happy to start in this community,
I have a question, I have a scene that gets data from a database in json, and then I use in a scene. Normally you would do it with a setInterval. But I have the init in the async function. How should this situation be implemented?
Thank you very much for the help.
let scene, camera, renderer, mesh, object, controls, mixer, clock;
let loadingManager;
const getDataAsync = async () => {
const result = await fetch("functions/test.php", {
method: "POST",
});
const object = await result.json();
init(object);
controls.addEventListener("change", onPositionChange);
window.addEventListener("resize", resize);
onmousemove = function (e) {
document.getElementById("mouse").textContent = e.clientX + " " + e.clientY;
};
};
getDataAsync();
setInterval(getDataAsync, 60000);
function init(object) {
Scene...
Camera...
Geometry...
Material...
...
}
Have you considered to have two functions for setting up your scene? You could use init()
which only sets up the basic scene entities (like camera
, renderer
, scene
etc.) and then a second function that processes the responses of your backend requests. I assume the second function would just add 3D objects to the scene (depending on what data are defined in your database).
350 / 5000
If exactly, the backend part provides positions and names for the models inserted via GLTFLoader. But for now they are called inside the Init () function, the database provides new data every 5 minutes so the setInterval thing. I need the scene that is going to have animations to update with the data every minute.
Hello again,
finally I have separated all the functions and it has been as follows:
function initThree(){
initRender();
initScene();
initLoading();
initCamera();
initLight();
initObject();
initListener();
getDataAsync();
animate();
}
function animate() {}
function render() {}
const getDataAsync = async () => {}
initThree();
setInterval(getDataAsync, 60000);
If you see a better alternative, I would appreciate your advice.
Thanks.
Hi @World_Data
Usually setInterval() it’s used to set a delay, but it’is not a good solution in order to receive data from a server, it could work sometimes but at the first connection slowdown you’ll find an error.
1)Wait the first response from the server in order to execute the function where your json data is used … something like this that I used in a similar process
fetch(my_api_url, {
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
})
.then((response) => {
if (response.status !== 200) {
console.log(
`Looks like there was a problem. Status Code: ${response.status}`,
);
return;
}
return response.json();
})
.then((data) => {
init(data); // here is the data transfer to threejs init()
animate(); // ecc
})
.catch((err) => {
console.log('Fetch Error :-S', err);
});
- you need to update your json data?
If you need an HiFi solution you can evaluate a web socket (like socket.io)… you’ll find many examples online
Important:
Please don’t “extimate” your server requests and responses time in millisenconds… the best practice is to wait the responce before executing your code.
Hi again,
thanks for your answer @alessandro_guarino.
I have a function with async await that does just that, it is true that at the moment I do not control if it does not have a result, I will implement it. The setInterval I use to get the new data from the database every minute, but I find the problem that the objects in the scene are duplicated, I should delete them before downloading them again.
This is the asynchronous function:
function removeGLTFObjects() {
for (let i = scene.children.length - 1; i >= 0; i--) {
if (scene.children[i].type === "Group")
scene.remove(scene.children[i]);
}
}
const getDataAsync = async () => {
const result = await fetch("my_api_url", {
method: "POST",
});
const object = await result.json();
removeGLTFObjects();
getDataFromJSON(object);
};
initThree();
setInterval(getDataAsync, 60000);
and at the moment I am trying to delete the objects like this, but I do not get the desired result …
Sorry, I’m not sure to have understood.
Have you a problem with async json and initial settings?
If Yes:
Your initThree() looks not async data related, and of course it’s exetuted before you have the first json result (one second delay).
This could be a problem.
I suggest you to separate the first data request from the others.
Usually people needs to collect data before to call init() function, but I don’t know your project.
After the first request, when all it’s started correctly, you can repeat your request with another funcrion to update your javascript object in runtime, but don’t execute init() twice … it’s not good
Anyway I see that you call getDataAsync only once.
In order to repeat your request every minute I think you have to make your function “recursive” (calling itself from inside).
So I think that you need something similar to this, but I dont know what happens inside getDataFromJSON and initThree:
const getDataAsyncInit = async () => {
const result = await fetch("my_api_url", {
method: "POST",
});
const object = await result.json();
//removeGLTFObjects(); //before init you have nothing to remove
getDataFromJSON(object);
initThree();//init after result
};
getDataAsyncInit(); //without delay in my opinion
const getDataAsyncRuntime = async () => {
const result = await fetch("my_api_url", {
method: "POST",
});
const object = await result.json();
removeGLTFObjects();//now it's possible that you have somethig to delete
getDataFromJSON(object);
setInterval(getDataAsyncRuntime, 60000);//recall from inside
};
setInterval(getDataAsyncRuntime, 60000); // second function with delay
No data problem? You have a problem with removeGLTFObjects()?
Are your objects only groups? Are you sure it’s executed?
Add some console.log in order to know where your code fails
function removeGLTFObjects() {
console.log("I try to remove");
for (let i = scene.children.length - 1; i >= 0; i--) {
if (scene.children[i].type === "Group") {
console.log("It's a group");
scene.remove(scene.children[i]);
}else{
console.log("It's not a group");
}
}
}
I hope it can help
Thanks again for your help @alessandro_guarino .
I don’t call InitThree () twice.
the getDataFromJSON function:
function getDataFromJSON(object) {
fetch("assets/json/wkas.json")
.then((response) => response.json())
.then((data) => combineDataObject(object, data))
.catch((err) => console.log(err));
}
function combineDataObject(dataDB, datajson) {
const result = datajson.wka.map((v) => ({ ...v,...dataDB.wka.find((sp) => sp.name === v.name),
}));
loadDataWkas(result); // load geometry GLTF with params
}
I use it to take some data from an internal json and join them to those that come from the database, and then load the models with the final result as positions, and orientation.
Thank you!
Oook
so you’ve changed your starting code, here was called twice
const getDataAsync = async () => {
const result = await fetch("functions/test.php", {
method: "POST",
});
const object = await result.json();
init(object);
...
};
getDataAsync();
setInterval(getDataAsync, 60000);
Sorry for the misunderstanding, I think is not a complex problem but with code fragments it’s difficult to help.
I suggest to share an extended code, better a running sample
PS:
Interesting Proj …really!
Do your instances rorate according weather forecasts or meteo stations (wind speed and direction) from a server API?
If so, every minute I have new data in the database like wind direction and speed apart from more specific parameters that I represent in the scene. That is why these doubts about renewing the models every minute with different values.