电场矢量可视化求助:合成矢量箭头方向异常排查
电场合成矢量箭头方向问题排查
我已调整过电场可视化项目,目前包含三个canvas:canvas1(绿色电荷)、canvas2(蓝色电荷)、canvas3(合力),核心问题是部分箭头的方向表现不符合预期。以下是计算合成矢量方向的关键代码及完整函数:
合成矢量方向计算代码片段
let angleBetween; let anguloResultante; let alpha; let cosAlpha; let sinAlpha; let eR; //if the 2 charges are positve do all of this if(q1Value && q2Value > 0){ //rotation of the canvas(electric arrows) canvas1.style.transform = `rotate(${positivo1}deg)`; canvas2.style.transform = `rotate(${positivo2}deg)`; //Here im getting the angleBetween if(positivo1 > positivo2){ angleBetween = positivo1 - positivo2; if(angleBetween > 180){ angleBetween = 360 - angleBetween ; } alpha = 180 - angleBetween; cosAlpha = Math.cos(alpha*Math.PI/180); sinAlpha = Math.sin(alpha*Math.PI/180); eR = Math.sqrt(Math.pow(e1,2) + Math.pow(e2,2) - 2*e1*e2*cosAlpha) anguloResultante = (Math.asin(sinAlpha/eR)*e1) * 180 / Math.PI; if(positivo1 > 0 && positivo1 < 90){ canvas3.style.transform = `rotate(${anguloResultante}deg)`; } if(positivo1 > 90 && positivo1 < 180){ canvas3.style.transform = `rotate(${anguloResultante+90}deg)`; } if(positivo1 > 180 && positivo1 < 270){ canvas3.style.transform = `rotate(${anguloResultante+180}deg)`; } if(positivo1 > 270){ canvas3.style.transform = `rotate(${anguloResultante+270}deg)`; } } //Here im getting the angleBetween if(positivo2 > positivo1){ angleBetween = positivo2 - positivo1; if(angleBetween > 180){ angleBetween = 360 - angleBetween ; } alpha = 180 - angleBetween; cosAlpha = Math.cos(alpha*Math.PI/180); sinAlpha = Math.sin(alpha*Math.PI/180); eR = Math.sqrt(Math.pow(e1,2) + Math.pow(e2,2) - 2*e1*e2*cosAlpha) anguloResultante = (Math.asin(sinAlpha/eR)*e2) * 180 / Math.PI; if(positivo2 > 0 && positivo2 < 90){ canvas3.style.transform = `rotate(${anguloResultante}deg)`; } if(positivo2 > 90 && positivo2 < 180){ canvas3.style.transform = `rotate(${anguloResultante+90}deg)`; } if(positivo2 > 180 && positivo2 < 270){ canvas3.style.transform = `rotate(${anguloResultante+180}deg)`; } if(positivo2 > 270){ canvas3.style.transform = `rotate(${anguloResultante+270}deg)`; } }
完整事件处理函数
document.addEventListener('mousemove', ()=> { let distanceX = getDistanceBetweenElements(canvas1, x)/100; let distanceY = getDistanceBetweenElements(canvas1, y)/100; let e1 = (k*q1)/Math.pow(distanceX,2); let e2 = (k*q2)/Math.pow(distanceY,2); let Q1x = getPositionAtCenter(document.getElementById('x')).x; let Q1y = getPositionAtCenter(document.getElementById('x')).y; let Q2x = getPositionAtCenter(document.getElementById('y')).x; let Q2y = getPositionAtCenter(document.getElementById('y')).y; const rekt = canvas1.getBoundingClientRect(); const anchorX= rekt.left + rekt.width / 2; const anchorY= rekt.top + rekt.height / 2; let angleDeg1 = angle(Q1x, Q1y, anchorX, anchorY); let angleDeg2 = angle(Q2x, Q2y, anchorX, anchorY); let positivo1 = angleDeg1+180; let negativo1 = angleDeg1; let positivo2 = angleDeg2 + 180; let negativo2 = angleDeg2; let angleBetween; let anguloResultante; let alpha; let cosAlpha; let sinAlpha; let eR; if(q1Value && q2Value > 0){ canvas1.style.transform = `rotate(${positivo1}deg)`; canvas2.style.transform = `rotate(${positivo2}deg)`; if(positivo1 > positivo2){ angleBetween = positivo1 - positivo2; if(angleBetween > 180){ angleBetween = 360 - angleBetween ; } alpha = 180 - angleBetween; cosAlpha = Math.cos(alpha*Math.PI/180); sinAlpha = Math.sin(alpha*Math.PI/180); eR = Math.sqrt(Math.pow(e1,2) + Math.pow(e2,2) - 2*e1*e2*cosAlpha) anguloResultante = (Math.asin(sinAlpha/eR)*e1) * 180 / Math.PI; if(positivo1 > 0 && positivo1 < 90){ canvas3.style.transform = `rotate(${anguloResultante}deg)`; } if(positivo1 > 90 && positivo1 < 180){ canvas3.style.transform = `rotate(${anguloResultante+90}deg)`; } if(positivo1 > 180 && positivo1 < 270){ canvas3.style.transform = `rotate(${anguloResultante+180}deg)`; } if(positivo1 > 270){ canvas3.style.transform = `rotate(${anguloResultante+270}deg)`; } } if(positivo2 > positivo1){ angleBetween = positivo2 - positivo1; if(angleBetween > 180){ angleBetween = 360 - angleBetween ; } alpha = 180 - angleBetween; cosAlpha = Math.cos(alpha*Math.PI/180); sinAlpha = Math.sin(alpha*Math.PI/180); eR = Math.sqrt(Math.pow(e1,2) + Math.pow(e2,2) - 2*e1*e2*cosAlpha) anguloResultante = (Math.asin(sinAlpha/eR)*e2) * 180 / Math.PI; if(positivo2 > 0 && positivo2 < 90){ canvas3.style.transform = `rotate(${anguloResultante}deg)`; } if(positivo2 > 90 && positivo2 < 180){ canvas3.style.transform = `rotate(${anguloResultante+90}deg)`; } if(positivo2 > 180 && positivo2 < 270){ canvas3.style.transform = `rotate(${anguloResultante+180}deg)`; } if(positivo2 > 270){ canvas3.style.transform = `rotate(${anguloResultante+270}deg)`; } } } if(q1Value && q2Value < 0){ canvas1.style.transform = `rotate(${negativo1}deg)`; canvas2.style.transform = `rotate(${negativo2}deg)`; } if(q1Value > 0 && q2Value < 0){ canvas1.style.transform = `rotate(${positivo1}deg)`; canvas2.style.transform = `rotate(${negativo2}deg)`; } if(q1Value < 0 && q2Value > 0){ canvas1.style.transform = `rotate(${negativo1}deg)`; canvas2.style.transform = `rotate(${positivo2}deg)`; } }); btnSubmit.addEventListener('click', () =>{ q1Value = document.getElementById('valor1').value; q1Potencia = document.getElementById('potencia1').value; q1Prefijo = document.getElementById('prefijo1').value; q2Value = document.getElementById('valor2').value; q2Potencia = document.getElementById('potencia2').value; q2Prefijo = document.getElementById('prefijo2').value; if(q1Value > 0 || q1Value < 0){ if(q1Prefijo == '1'){ q1 = q1Value * Math.pow(10, q1Potencia); }else if(q1Prefijo == '2'){ q1 = (q1Value * Math.pow(10, q1Potencia)) / 1e+6; }else if(q1Prefijo == '3'){ q1 = (q1Value * Math.pow(10, q1Potencia)) / 1e+12; }else if(q1Prefijo == '4'){ q1 = (q1Value * Math.pow(10, q1Potencia)) / 1e+9; } } if(q2Value > 0 || q2Value < 0){ if(q2Prefijo == '1'){ q2 = q2Value * Math.pow(10, q2Potencia); }else if(q2Prefijo == '2'){ q2 = (q2Value * Math.pow(10, q2Potencia)) / 1e+6; }else if(q2Prefijo == '3'){ q2 = (q2Value * Math.pow(10, q2Potencia)) / 1e+12; }else if(q2Prefijo == '4'){ q2 = (q2Value * Math.pow(10, q2Potencia)) / 1e+9; } } //makes q1 and q2 dragabbles const dragX = (e) =>{ x.style.left = e.pageX + 'px'; x.style.top = e.pageY + 'px'; } x.addEventListener('mousedown', () => { window.addEventListener("mousemove", dragX); }); window.addEventListener("mouseup", () => { window.removeEventListener("mousemove", dragX); }); const dragY = (e) =>{ y.style.left = e.pageX + 'px'; y.style.top = e.pageY + 'px'; } y.addEventListener('mousedown', () => { window.addEventListener("mousemove", dragY); }); window.addEventListener("mouseup", () => { window.removeEventListener("mousemove", dragY); }); //Accion createArrow for(let i = 0; i < 104; i++) { createArrow(); } });
关键问题分析及修复建议
- Math.asin的取值范围限制:
Math.asin()的返回值范围是[-π/2, π/2],仅能表示第一、四象限的角度,无法覆盖所有方向,这会导致计算出的anguloResultante存在方向歧义,进而错误设置canvas3的旋转角度。建议改用矢量分量合成法计算合力方向:// 计算两个电场的x、y分量(基于positivo1/positivo2的弧度值) const rad1 = positivo1 * Math.PI / 180; const rad2 = positivo2 * Math.PI / 180; const e1x = e1 * Math.cos(rad1); const e1y = e1 * Math.sin(rad1); const e2x = e2 * Math.cos(rad2); const e2y = e2 * Math.sin(rad2); // 合成合力的分量 const eRx = e1x + e2x; const eRy = e1y + e2y; // 计算合力的角度(使用Math.atan2覆盖所有象限) const anguloResultanteRad = Math.atan2(eRy, eRx); const anguloResultanteDeg = anguloResultanteRad * 180 / Math.PI; // 直接设置canvas3的旋转角度,无需分象限加偏移 canvas3.style.transform = `rotate(${anguloResultanteDeg}deg)`; - 分象限偏移逻辑错误:原代码中根据positivo1/positivo2的区间手动添加90/180/270度偏移的逻辑完全依赖角度比较,没有考虑矢量的实际方向,容易出现错误偏移。使用矢量分量合成后,无需手动分象限调整,
Math.atan2会自动返回正确的全象限角度。 - 角度计算冗余:原代码中计算
angleBetween和alpha的步骤可以简化,直接使用矢量分量法更直观且不易出错。
内容的提问来源于stack exchange,提问作者Nashe
相关产品推荐
相关产品推荐

