Im programming a magnetic field simulator with a max of 4 charges but i dont understand what is wrong with the angle calculation.
function generarCargas is the function that creates the arrows, sorry if i didnt comment, if you have any questions with the code i will answer immediately.
JS:
//Funcion angle
function angle(cx, cy, ex, ey) {
const dy = ey - cy;
const dx = ex - cx;
const rad = Math.atan2(dy, dx);
const deg = (rad * 180) / Math.PI;
return deg;
}
//Funcion getPositionAtCenter
function getPositionAtCenter(element) {
const { top, left, width, height } = element.getBoundingClientRect();
return {
x: left + width / 2,
y: top + height / 2,
};
}
//Funcion getDistanceBetweenElements
function getDistanceBetweenElements(a, b) {
const aPosition = getPositionAtCenter(a);
const bPosition = getPositionAtCenter(b);
return Math.hypot(aPosition.x - bPosition.x, aPosition.y - bPosition.y);
}
function generarCargas(selectValues) {
const arrows = document.querySelectorAll(".arrow");
selectValues.forEach((carga) => {
const cargaDiv = document.createElement("div");
cargaDiv.className = "carga";
const div = document.createElement("div");
cargaDiv.appendChild(div);
div.textContent = carga;
allCampo.appendChild(cargaDiv);
valoresCarga = carga;
});
let dragItem = null;
let offsetX = 0;
let offsetY = 0;
allCampo.addEventListener("mousedown", (e) => {
const cargaDiv = e.target.closest(".carga");
if (cargaDiv) {
dragItem = cargaDiv;
offsetX = e.clientX - cargaDiv.getBoundingClientRect().left;
offsetY = e.clientY - cargaDiv.getBoundingClientRect().top;
document.addEventListener("mousemove", handleDrag);
document.addEventListener("mouseup", () => {
document.removeEventListener("mousemove", handleDrag);
dragItem = null;
});
function handleDrag(e) {
if (dragItem) {
const posX = e.clientX - offsetX;
const posY = e.clientY - offsetY;
dragItem.style.left = posX + "px";
dragItem.style.top = posY + "px";
}
const cargas = document.querySelectorAll(".carga");
arrows.forEach((arrow) => {
let angles = [];
let eRx = 0;
let eRy = 0;
let resultantAngle;
cargas.forEach((carga, index) => {
let qx = getPositionAtCenter(carga).x;
let qy = getPositionAtCenter(carga).y;
let distancia = getDistanceBetweenElements(arrow, carga) / 100;
let e;
const rekt = arrow.getBoundingClientRect();
const anchorX = rekt.left + rekt.width / 2;
const anchorY = rekt.top + rekt.height / 2;
let angleDeg = angle(qx, qy, anchorX, anchorY);
let cargaValue = parseInt(carga.textContent);
if (cargaValue < 0) {
angleDeg = angleDeg - 180;
cargaValue = -cargaValue;
}
e = (k * cargaValue) / Math.pow(distancia, 2);
let ex = e * Math.cos((angleDeg * Math.PI) / 180);
let ey = e * Math.sin((angleDeg * Math.PI) / 180);
eRx += ex;
eRy += ey;
angles.push(angleDeg);
});
let resultant = Math.sqrt(Math.pow(eRx, 2) + Math.pow(eRy, 2));
let tanAlpha = eRy / eRx;
let alpha = (Math.atan(tanAlpha) * 180) / Math.PI;
arrow.style.transform = "rotate(" + alpha + "deg)";
});
}
}
});
}
Image of the resultant arrows:
Results
>Solution :
It seems like your code is mostly set up correctly to calculate the angles for simulating a magnetic field. However, there might be an issue with how you’re handling the angle calculation, especially when considering multiple charges and their cumulative effect. Here are a few suggestions and a code snippet to potentially resolve the issue:
- Angle Calculation with Multiple Charges: When dealing with multiple charges, you need to calculate the resultant vector from all the individual vectors (due to each charge). Your code seems to be doing this, but there might be an issue with how the angles are summed up or how the resultant is calculated.
- Handling Negative Charges: You’ve included a condition to subtract 180 degrees from the angle if the charge is negative. This might not be the best way to handle negative charges. The direction of the force due to a negative charge should be opposite to that of a positive charge, but this doesn’t necessarily translate to a 180-degree shift.
- Resultant Vector Calculation: The resultant vector calculation seems to be correct, but ensure that the calculation of
tanAlpha
andalpha
is done correctly. It might be more robust to useMath.atan2(eRy, eRx)
instead, as it handles all quadrants and the possibility of a zero denominator.
Here’s a revised attempt for the part of your code where you calculate the angle for each arrow:
// Inside handleDrag function
arrows.forEach((arrow) => {
let eRx = 0;
let eRy = 0;
cargas.forEach((carga) => {
const { x: qx, y: qy } = getPositionAtCenter(carga);
const distancia = getDistanceBetweenElements(arrow, carga) / 100;
const cargaValue = parseInt(carga.textContent);
const rekt = arrow.getBoundingClientRect();
const anchorX = rekt.left + rekt.width / 2;
const anchorY = rekt.top + rekt.height / 2;
let angleDeg = angle(qx, qy, anchorX, anchorY);
let e = (k * Math.abs(cargaValue)) / Math.pow(distancia, 2);
// Adjust direction for negative charges
if (cargaValue < 0) {
angleDeg += 180;
}
let ex = e * Math.cos((angleDeg * Math.PI) / 180);
let ey = e * Math.sin((angleDeg * Math.PI) / 180);
eRx += ex;
eRy += ey;
});
let alpha = Math.atan2(eRy, eRx) * (180 / Math.PI);
arrow.style.transform = `rotate(${alpha}deg)`;
});
This revision uses Math.atan2
for a more accurate calculation of the angle and ensures that negative charges are handled by simply adjusting the angle by 180 degrees. This should more accurately represent the physics of magnetic fields with multiple charges.