Estoy tratando de crear círculos SVG colocados al azar, pero no quiero que estén demasiado cerca uno del otro. Estoy usando firestore para el backend y d3.js para crear círculos. Cada círculo se coloca debido a su "xValue" y "yValue" en firebase, que se generan usando Math.random. Estos valores (coordenadas) deben crearse de una manera especial diferente para evitar círculos demasiado cerrados.
Mi primer enfoque fue usar Math.random nuevamente, pero verifique todos los xValues y yValues existentes para encontrar la distancia entre el círculo que estoy a punto de crear, luego, si la distancia es inferior a 80, aumente Math.random valor 100. No lo hace trabajo
function createRandomCoordinates() { var coordinates = []; getDocs(collection(db, "circles")).then((querySnapshot) => { querySnapshot.forEach((doc) => { coordinates.push({ ...doc.data() }); }) }); let randomXValue = Math.floor(Math.random()*1200); let randomYValue = Math.floor(Math.random()*1200); var distances = []; for (let i = 0; i < coordinates.length; i++) { var a = coordinates[i].xValue - randomXValue; var b = coordinates[i].yValue - randomYValue; var distance = Math.sqrt(a * a + b * b); distances.push(distance); if(distances.some((e) => e < 80)){ return { randXVal: randomXValue + 100, randYVal: randomYValue + 100 } }else { return { randXVal: randomXValue, randYVal: randomYValue } } } } console.log(createRandomCoordinates().randXVal,createRandomCoordinates().randYVal )getDocs es una llamada asíncrona, ya que necesita leer datos del servidor. Mientras se leen los datos, su código principal continúa ejecutándose para que el usuario pueda continuar usando la aplicación. Luego, cuando los datos están disponibles, su devolución de llamada se invoca con esos datos.
En la práctica, esto significa que for (let i = 0; i < coordinates.length; i++) { loop se llama antes de que suceda cualquiera de las coordinates.push({ ...doc.data() }) , por lo que siempre está en bucle sobre una matriz vacía.
La solución es siempre la misma: el código que necesita los datos debe estar dentro de la devolución de llamada o sincronizarse de otra manera (como a través de una devolución de llamada o una promesa).
La solución más simple es mover el código que usa las coordenadas a la devolución de llamada, después del bucle:
function createRandomCoordinates() { return getDocs(collection(db, "circles")).then((querySnapshot) => { const coordinates = querySnapshot.docs.map((doc) => doc.data()); let randomXValue = Math.floor(Math.random()*1200); let randomYValue = Math.floor(Math.random()*1200); var distances = []; for (let i = 0; i < coordinates.length; i++) { var a = coordinates[i].xValue - randomXValue; var b = coordinates[i].yValue - randomYValue; var distance = Math.sqrt(a * a + b * b); distances.push(distance); if(distances.some((e) => e < 80)){ return { randXVal: randomXValue + 100, randYVal: randomYValue + 100 } } else { return { randXVal: randomXValue, randYVal: randomYValue } } } //missing curly bracket }); }Ver también: