| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Electric Field Calculator</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
| <style> |
| .gradient-bg { |
| background: linear-gradient(135deg, #6b73ff 0%, #000dff 100%); |
| } |
| .particle { |
| position: absolute; |
| border-radius: 50%; |
| pointer-events: none; |
| } |
| .canvas-container { |
| position: relative; |
| width: 100%; |
| height: 300px; |
| background-color: #f8f9fa; |
| border-radius: 0.5rem; |
| overflow: hidden; |
| } |
| #fieldCanvas { |
| width: 100%; |
| height: 100%; |
| } |
| .slider-thumb::-webkit-slider-thumb { |
| -webkit-appearance: none; |
| appearance: none; |
| width: 20px; |
| height: 20px; |
| border-radius: 50%; |
| background: #4f46e5; |
| cursor: pointer; |
| } |
| .slider-thumb::-moz-range-thumb { |
| width: 20px; |
| height: 20px; |
| border-radius: 50%; |
| background: #4f46e5; |
| cursor: pointer; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-50 min-h-screen"> |
| <div class="gradient-bg text-white py-8 shadow-lg"> |
| <div class="container mx-auto px-4"> |
| <div class="flex items-center justify-between"> |
| <div> |
| <h1 class="text-3xl font-bold"><i class="fas fa-bolt mr-2"></i>Electric Field Calculator</h1> |
| <p class="mt-2 opacity-90">Visualize and calculate electric fields from point charges</p> |
| </div> |
| <div class="hidden md:block"> |
| <div class="flex space-x-2"> |
| <div class="particle" style="width: 8px; height: 8px; background: rgba(255,255,255,0.6); top: 20px; left: 10px;"></div> |
| <div class="particle" style="width: 12px; height: 12px; background: rgba(255,255,255,0.8); top: 10px; left: 30px;"></div> |
| <div class="particle" style="width: 6px; height: 6px; background: rgba(255,255,255,0.4); top: 25px; left: 50px;"></div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="container mx-auto px-4 py-8"> |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> |
| |
| <div class="bg-white rounded-xl shadow-md p-6 lg:col-span-1"> |
| <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center"> |
| <i class="fas fa-calculator mr-2 text-indigo-600"></i> Calculator Parameters |
| </h2> |
| |
| <div class="space-y-6"> |
| |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Charge 1 (q₁)</label> |
| <div class="flex items-center space-x-2"> |
| <input type="range" min="-100" max="100" value="50" class="w-full slider-thumb" id="charge1Slider"> |
| <input type="number" id="charge1Input" value="50" class="w-20 px-3 py-2 border border-gray-300 rounded-md text-sm"> |
| <span class="text-sm text-gray-500">μC</span> |
| </div> |
| </div> |
| |
| |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Position (x₁)</label> |
| <div class="flex items-center space-x-2"> |
| <input type="range" min="0" max="300" value="100" class="w-full slider-thumb" id="position1Slider"> |
| <input type="number" id="position1Input" value="100" class="w-20 px-3 py-2 border border-gray-300 rounded-md text-sm"> |
| <span class="text-sm text-gray-500">cm</span> |
| </div> |
| </div> |
| |
| |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Charge 2 (q₂)</label> |
| <div class="flex items-center space-x-2"> |
| <input type="range" min="-100" max="100" value="-30" class="w-full slider-thumb" id="charge2Slider"> |
| <input type="number" id="charge2Input" value="-30" class="w-20 px-3 py-2 border border-gray-300 rounded-md text-sm"> |
| <span class="text-sm text-gray-500">μC</span> |
| </div> |
| </div> |
| |
| |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Position (x₂)</label> |
| <div class="flex items-center space-x-2"> |
| <input type="range" min="0" max="300" value="200" class="w-full slider-thumb" id="position2Slider"> |
| <input type="number" id="position2Input" value="200" class="w-20 px-3 py-2 border border-gray-300 rounded-md text-sm"> |
| <span class="text-sm text-gray-500">cm</span> |
| </div> |
| </div> |
| |
| |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-1">Test Position (x)</label> |
| <div class="flex items-center space-x-2"> |
| <input type="range" min="0" max="300" value="150" class="w-full slider-thumb" id="testPositionSlider"> |
| <input type="number" id="testPositionInput" value="150" class="w-20 px-3 py-2 border border-gray-300 rounded-md text-sm"> |
| <span class="text-sm text-gray-500">cm</span> |
| </div> |
| </div> |
| |
| <button id="calculateBtn" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-4 rounded-md font-medium transition duration-300 flex items-center justify-center"> |
| <i class="fas fa-bolt mr-2"></i> Calculate Electric Field |
| </button> |
| </div> |
| </div> |
| |
| |
| <div class="lg:col-span-2 space-y-6"> |
| |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center"> |
| <i class="fas fa-chart-bar mr-2 text-indigo-600"></i> Calculation Results |
| </h2> |
| |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> |
| <div class="bg-gray-50 p-4 rounded-lg"> |
| <p class="text-sm text-gray-500">Field from q₁</p> |
| <p id="field1Result" class="text-lg font-semibold">0 N/C</p> |
| </div> |
| <div class="bg-gray-50 p-4 rounded-lg"> |
| <p class="text-sm text-gray-500">Field from q₂</p> |
| <p id="field2Result" class="text-lg font-semibold">0 N/C</p> |
| </div> |
| <div class="bg-indigo-50 p-4 rounded-lg border border-indigo-100"> |
| <p class="text-sm text-indigo-600">Total Electric Field</p> |
| <p id="totalFieldResult" class="text-xl font-bold text-indigo-700">0 N/C</p> |
| </div> |
| </div> |
| |
| <div class="mt-6"> |
| <h3 class="font-medium text-gray-700 mb-2">Force Direction</h3> |
| <div id="forceDirection" class="flex items-center"> |
| <div class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center mr-2"> |
| <i class="fas fa-question text-gray-500"></i> |
| </div> |
| <span class="text-gray-600">No calculation yet</span> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center"> |
| <i class="fas fa-project-diagram mr-2 text-indigo-600"></i> Field Visualization |
| </h2> |
| |
| <div class="canvas-container"> |
| <canvas id="fieldCanvas"></canvas> |
| </div> |
| |
| <div class="mt-4 flex justify-between items-center"> |
| <div class="flex items-center"> |
| <div class="w-4 h-4 rounded-full bg-red-500 mr-2"></div> |
| <span class="text-sm text-gray-600">Positive charge</span> |
| </div> |
| <div class="flex items-center"> |
| <div class="w-4 h-4 rounded-full bg-blue-500 mr-2"></div> |
| <span class="text-sm text-gray-600">Negative charge</span> |
| </div> |
| <div class="flex items-center"> |
| <div class="w-4 h-4 rounded-full bg-green-500 mr-2"></div> |
| <span class="text-sm text-gray-600">Test position</span> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center"> |
| <i class="fas fa-chart-line mr-2 text-indigo-600"></i> Field Strength Along Axis |
| </h2> |
| |
| <div class="h-64"> |
| <canvas id="fieldGraph"></canvas> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="mt-12 bg-white rounded-xl shadow-md p-6"> |
| <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center"> |
| <i class="fas fa-atom mr-2 text-indigo-600"></i> Physics Behind the Calculation |
| </h2> |
| |
| <div class="prose max-w-none"> |
| <p>The electric field <strong>E</strong> at a point in space due to a point charge is given by Coulomb's Law:</p> |
| <div class="bg-gray-50 p-4 rounded-lg my-3"> |
| <p class="text-center font-mono text-lg">E = k * |q| / r²</p> |
| </div> |
| <p>Where:</p> |
| <ul class="list-disc pl-5 space-y-1"> |
| <li><strong>E</strong> is the magnitude of the electric field (N/C)</li> |
| <li><strong>k</strong> is Coulomb's constant (8.99 × 10⁹ N·m²/C²)</li> |
| <li><strong>q</strong> is the charge (C)</li> |
| <li><strong>r</strong> is the distance from the charge to the point (m)</li> |
| </ul> |
| |
| <p class="mt-4">For multiple charges, the total electric field is the <strong>vector sum</strong> of the fields from each individual charge. In this 1D calculator, we simply add or subtract the field magnitudes based on their direction.</p> |
| |
| <div class="bg-indigo-50 border-l-4 border-indigo-400 p-4 mt-4"> |
| <p class="text-indigo-800"><strong>Note:</strong> In this calculator, we're working in one dimension (along the x-axis) for simplicity. In real 2D or 3D space, electric fields are vectors that require vector addition to combine properly.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <footer class="bg-gray-800 text-white py-6 mt-12"> |
| <div class="container mx-auto px-4"> |
| <div class="flex flex-col md:flex-row justify-between items-center"> |
| <div class="mb-4 md:mb-0"> |
| <h3 class="text-lg font-semibold">Electric Field Calculator</h3> |
| <p class="text-gray-400 text-sm">A tool for visualizing electric fields</p> |
| </div> |
| <div class="flex space-x-4"> |
| <a href="#" class="text-gray-400 hover:text-white transition"> |
| <i class="fab fa-github text-xl"></i> |
| </a> |
| <a href="#" class="text-gray-400 hover:text-white transition"> |
| <i class="fas fa-envelope text-xl"></i> |
| </a> |
| </div> |
| </div> |
| <div class="mt-4 pt-4 border-t border-gray-700 text-center text-gray-400 text-sm"> |
| <p>Created for educational purposes. Not for professional use.</p> |
| </div> |
| </div> |
| </footer> |
|
|
| <script> |
| |
| const k = 8.99e9; |
| const scaleFactor = 1e6; |
| |
| |
| const charge1Slider = document.getElementById('charge1Slider'); |
| const charge1Input = document.getElementById('charge1Input'); |
| const position1Slider = document.getElementById('position1Slider'); |
| const position1Input = document.getElementById('position1Input'); |
| |
| const charge2Slider = document.getElementById('charge2Slider'); |
| const charge2Input = document.getElementById('charge2Input'); |
| const position2Slider = document.getElementById('position2Slider'); |
| const position2Input = document.getElementById('position2Input'); |
| |
| const testPositionSlider = document.getElementById('testPositionSlider'); |
| const testPositionInput = document.getElementById('testPositionInput'); |
| |
| const calculateBtn = document.getElementById('calculateBtn'); |
| |
| const field1Result = document.getElementById('field1Result'); |
| const field2Result = document.getElementById('field2Result'); |
| const totalFieldResult = document.getElementById('totalFieldResult'); |
| const forceDirection = document.getElementById('forceDirection'); |
| |
| |
| const canvas = document.getElementById('fieldCanvas'); |
| const ctx = canvas.getContext('2d'); |
| |
| |
| const graphCanvas = document.getElementById('fieldGraph'); |
| const graphCtx = graphCanvas.getContext('2d'); |
| let fieldGraph; |
| |
| |
| function resizeCanvas() { |
| const container = document.querySelector('.canvas-container'); |
| canvas.width = container.clientWidth; |
| canvas.height = container.clientHeight; |
| graphCanvas.width = graphCanvas.parentElement.clientWidth; |
| graphCanvas.height = graphCanvas.parentElement.clientHeight; |
| drawField(); |
| } |
| |
| |
| window.addEventListener('load', () => { |
| resizeCanvas(); |
| initializeGraph(); |
| setupEventListeners(); |
| calculateElectricField(); |
| }); |
| |
| window.addEventListener('resize', () => { |
| resizeCanvas(); |
| updateGraph(); |
| }); |
| |
| function setupEventListeners() { |
| |
| charge1Slider.addEventListener('input', (e) => { |
| charge1Input.value = e.target.value; |
| calculateElectricField(); |
| }); |
| charge1Input.addEventListener('input', (e) => { |
| const val = Math.min(100, Math.max(-100, parseInt(e.target.value) || 0)); |
| charge1Slider.value = val; |
| charge1Input.value = val; |
| calculateElectricField(); |
| }); |
| |
| |
| position1Slider.addEventListener('input', (e) => { |
| position1Input.value = e.target.value; |
| calculateElectricField(); |
| }); |
| position1Input.addEventListener('input', (e) => { |
| const val = Math.min(300, Math.max(0, parseInt(e.target.value) || 0)); |
| position1Slider.value = val; |
| position1Input.value = val; |
| calculateElectricField(); |
| }); |
| |
| |
| charge2Slider.addEventListener('input', (e) => { |
| charge2Input.value = e.target.value; |
| calculateElectricField(); |
| }); |
| charge2Input.addEventListener('input', (e) => { |
| const val = Math.min(100, Math.max(-100, parseInt(e.target.value) || 0)); |
| charge2Slider.value = val; |
| charge2Input.value = val; |
| calculateElectricField(); |
| }); |
| |
| |
| position2Slider.addEventListener('input', (e) => { |
| position2Input.value = e.target.value; |
| calculateElectricField(); |
| }); |
| position2Input.addEventListener('input', (e) => { |
| const val = Math.min(300, Math.max(0, parseInt(e.target.value) || 0)); |
| position2Slider.value = val; |
| position2Input.value = val; |
| calculateElectricField(); |
| }); |
| |
| |
| testPositionSlider.addEventListener('input', (e) => { |
| testPositionInput.value = e.target.value; |
| calculateElectricField(); |
| }); |
| testPositionInput.addEventListener('input', (e) => { |
| const val = Math.min(300, Math.max(0, parseInt(e.target.value) || 0)); |
| testPositionSlider.value = val; |
| testPositionInput.value = val; |
| calculateElectricField(); |
| }); |
| |
| |
| calculateBtn.addEventListener('click', calculateElectricField); |
| } |
| |
| function calculateElectricField() { |
| |
| const q1 = parseFloat(charge1Input.value) * 1e-6; |
| const x1 = parseFloat(position1Input.value) * 0.01; |
| const q2 = parseFloat(charge2Input.value) * 1e-6; |
| const x2 = parseFloat(position2Input.value) * 0.01; |
| const x = parseFloat(testPositionInput.value) * 0.01; |
| |
| |
| const r1 = Math.abs(x - x1); |
| const r2 = Math.abs(x - x2); |
| |
| |
| const E1 = q1 !== 0 ? k * Math.abs(q1) / (r1 * r1) : 0; |
| const E2 = q2 !== 0 ? k * Math.abs(q2) / (r2 * r2) : 0; |
| |
| |
| let dir1 = 0; |
| if (q1 > 0) { |
| dir1 = (x > x1) ? 1 : -1; |
| } else if (q1 < 0) { |
| dir1 = (x > x1) ? -1 : 1; |
| } |
| |
| let dir2 = 0; |
| if (q2 > 0) { |
| dir2 = (x > x2) ? 1 : -1; |
| } else if (q2 < 0) { |
| dir2 = (x > x2) ? -1 : 1; |
| } |
| |
| |
| const E1x = E1 * dir1; |
| const E2x = E2 * dir2; |
| const Etotal = E1x + E2x; |
| |
| |
| field1Result.textContent = `${E1x.toExponential(2)} N/C`; |
| field2Result.textContent = `${E2x.toExponential(2)} N/C`; |
| totalFieldResult.textContent = `${Etotal.toExponential(2)} N/C`; |
| |
| |
| updateForceDirection(Etotal); |
| |
| |
| drawField(); |
| |
| |
| updateGraph(); |
| } |
| |
| function updateForceDirection(Etotal) { |
| const directionIcon = forceDirection.querySelector('i'); |
| const directionText = forceDirection.querySelector('span'); |
| |
| if (Etotal > 0) { |
| directionIcon.className = 'fas fa-arrow-right text-green-500'; |
| directionText.textContent = 'Positive test charge would move to the right'; |
| directionText.className = 'text-green-600'; |
| forceDirection.querySelector('div').className = 'w-8 h-8 rounded-full bg-green-100 flex items-center justify-center mr-2'; |
| } else if (Etotal < 0) { |
| directionIcon.className = 'fas fa-arrow-left text-red-500'; |
| directionText.textContent = 'Positive test charge would move to the left'; |
| directionText.className = 'text-red-600'; |
| forceDirection.querySelector('div').className = 'w-8 h-8 rounded-full bg-red-100 flex items-center justify-center mr-2'; |
| } else { |
| directionIcon.className = 'fas fa-equals text-gray-500'; |
| directionText.textContent = 'No net force (equilibrium)'; |
| directionText.className = 'text-gray-600'; |
| forceDirection.querySelector('div').className = 'w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center mr-2'; |
| } |
| } |
| |
| function drawField() { |
| |
| ctx.clearRect(0, 0, canvas.width, canvas.height); |
| |
| |
| const x1 = parseFloat(position1Input.value) / 300 * canvas.width; |
| const x2 = parseFloat(position2Input.value) / 300 * canvas.width; |
| const x = parseFloat(testPositionInput.value) / 300 * canvas.width; |
| const q1 = parseFloat(charge1Input.value); |
| const q2 = parseFloat(charge2Input.value); |
| |
| |
| ctx.beginPath(); |
| ctx.moveTo(0, canvas.height / 2); |
| ctx.lineTo(canvas.width, canvas.height / 2); |
| ctx.strokeStyle = '#6b7280'; |
| ctx.lineWidth = 1; |
| ctx.stroke(); |
| |
| |
| ctx.beginPath(); |
| ctx.arc(x1, canvas.height / 2, 15, 0, Math.PI * 2); |
| ctx.fillStyle = q1 >= 0 ? '#ef4444' : '#3b82f6'; |
| ctx.fill(); |
| |
| |
| ctx.beginPath(); |
| ctx.arc(x2, canvas.height / 2, 15, 0, Math.PI * 2); |
| ctx.fillStyle = q2 >= 0 ? '#ef4444' : '#3b82f6'; |
| ctx.fill(); |
| |
| |
| ctx.beginPath(); |
| ctx.arc(x, canvas.height / 2, 10, 0, Math.PI * 2); |
| ctx.fillStyle = '#10b981'; |
| ctx.fill(); |
| |
| |
| ctx.font = 'bold 14px Arial'; |
| ctx.fillStyle = '#ffffff'; |
| ctx.textAlign = 'center'; |
| ctx.textBaseline = 'middle'; |
| |
| |
| ctx.fillText(q1 >= 0 ? '+' : '−', x1, canvas.height / 2); |
| |
| |
| ctx.fillText(q2 >= 0 ? '+' : '−', x2, canvas.height / 2); |
| |
| |
| drawFieldLines(x1, q1, x2, q2); |
| } |
| |
| function drawFieldLines(x1, q1, x2, q2) { |
| const centerY = canvas.height / 2; |
| const spacing = 20; |
| |
| |
| if (q1 !== 0) { |
| const lines1 = Math.min(10, Math.abs(q1) / 10); |
| for (let i = 0; i < lines1; i++) { |
| const angle = (i / lines1) * Math.PI * 2; |
| const startX = x1 + Math.cos(angle) * 20; |
| const startY = centerY + Math.sin(angle) * 20; |
| |
| let endX, endY; |
| if (q1 > 0) { |
| |
| endX = x1 + Math.cos(angle) * 40; |
| endY = centerY + Math.sin(angle) * 40; |
| } else { |
| |
| endX = x1 - Math.cos(angle) * 40; |
| endY = centerY - Math.sin(angle) * 40; |
| } |
| |
| drawArrow(startX, startY, endX, endY, q1 > 0 ? '#ef4444' : '#3b82f6'); |
| } |
| } |
| |
| |
| if (q2 !== 0) { |
| const lines2 = Math.min(10, Math.abs(q2) / 10); |
| for (let i = 0; i < lines2; i++) { |
| const angle = (i / lines2) * Math.PI * 2; |
| const startX = x2 + Math.cos(angle) * 20; |
| const startY = centerY + Math.sin(angle) * 20; |
| |
| let endX, endY; |
| if (q2 > 0) { |
| |
| endX = x2 + Math.cos(angle) * 40; |
| endY = centerY + Math.sin(angle) * 40; |
| } else { |
| |
| endX = x2 - Math.cos(angle) * 40; |
| endY = centerY - Math.sin(angle) * 40; |
| } |
| |
| drawArrow(startX, startY, endX, endY, q2 > 0 ? '#ef4444' : '#3b82f6'); |
| } |
| } |
| } |
| |
| function drawArrow(fromX, fromY, toX, toY, color) { |
| const headLength = 10; |
| const angle = Math.atan2(toY - fromY, toX - fromX); |
| |
| ctx.beginPath(); |
| ctx.strokeStyle = color; |
| ctx.lineWidth = 1.5; |
| |
| |
| ctx.moveTo(fromX, fromY); |
| ctx.lineTo(toX, toY); |
| ctx.stroke(); |
| |
| |
| ctx.beginPath(); |
| ctx.moveTo(toX, toY); |
| ctx.lineTo(toX - headLength * Math.cos(angle - Math.PI/6), toY - headLength * Math.sin(angle - Math.PI/6)); |
| ctx.moveTo(toX, toY); |
| ctx.lineTo(toX - headLength * Math.cos(angle + Math.PI/6), toY - headLength * Math.sin(angle + Math.PI/6)); |
| ctx.stroke(); |
| } |
| |
| function initializeGraph() { |
| fieldGraph = new Chart(graphCtx, { |
| type: 'line', |
| data: { |
| labels: Array.from({length: 31}, (_, i) => i * 10), |
| datasets: [ |
| { |
| label: 'Electric Field (N/C)', |
| data: [], |
| borderColor: '#4f46e5', |
| backgroundColor: 'rgba(79, 70, 229, 0.1)', |
| borderWidth: 2, |
| fill: true, |
| tension: 0.1 |
| } |
| ] |
| }, |
| options: { |
| responsive: true, |
| maintainAspectRatio: false, |
| scales: { |
| x: { |
| title: { |
| display: true, |
| text: 'Position (cm)' |
| } |
| }, |
| y: { |
| title: { |
| display: true, |
| text: 'Electric Field (N/C)' |
| } |
| } |
| }, |
| plugins: { |
| legend: { |
| position: 'top', |
| }, |
| tooltip: { |
| callbacks: { |
| label: function(context) { |
| return `E = ${context.parsed.y.toExponential(2)} N/C`; |
| } |
| } |
| } |
| } |
| } |
| }); |
| } |
| |
| function updateGraph() { |
| const q1 = parseFloat(charge1Input.value) * 1e-6; |
| const x1 = parseFloat(position1Input.value) * 0.01; |
| const q2 = parseFloat(charge2Input.value) * 1e-6; |
| const x2 = parseFloat(position2Input.value) * 0.01; |
| |
| const data = []; |
| |
| |
| for (let i = 0; i <= 300; i += 10) { |
| const x = i * 0.01; |
| |
| |
| const r1 = Math.abs(x - x1); |
| const r2 = Math.abs(x - x2); |
| |
| |
| const E1 = q1 !== 0 ? k * Math.abs(q1) / (r1 * r1) : 0; |
| const E2 = q2 !== 0 ? k * Math.abs(q2) / (r2 * r2) : 0; |
| |
| |
| let dir1 = 0; |
| if (q1 > 0) { |
| dir1 = (x > x1) ? 1 : -1; |
| } else if (q1 < 0) { |
| dir1 = (x > x1) ? -1 : 1; |
| } |
| |
| let dir2 = 0; |
| if (q2 > 0) { |
| dir2 = (x > x2) ? 1 : -1; |
| } else if (q2 < 0) { |
| dir2 = (x > x2) ? -1 : 1; |
| } |
| |
| |
| const E1x = E1 * dir1; |
| const E2x = E2 * dir2; |
| const Etotal = E1x + E2x; |
| |
| data.push(Etotal); |
| } |
| |
| |
| fieldGraph.data.datasets[0].data = data; |
| fieldGraph.update(); |
| } |
| |
| |
| function createParticles() { |
| const container = document.querySelector('.gradient-bg'); |
| for (let i = 0; i < 10; i++) { |
| const particle = document.createElement('div'); |
| particle.className = 'particle'; |
| |
| const size = Math.random() * 5 + 3; |
| const posX = Math.random() * 100; |
| const posY = Math.random() * 60; |
| const opacity = Math.random() * 0.5 + 0.3; |
| const duration = Math.random() * 10 + 10; |
| |
| particle.style.width = `${size}px`; |
| particle.style.height = `${size}px`; |
| particle.style.left = `${posX}%`; |
| particle.style.top = `${posY}%`; |
| particle.style.background = `rgba(255,255,255,${opacity})`; |
| particle.style.animation = `float ${duration}s linear infinite`; |
| |
| container.appendChild(particle); |
| } |
| } |
| |
| |
| const style = document.createElement('style'); |
| style.textContent = ` |
| @keyframes float { |
| 0% { |
| transform: translateY(0) translateX(0); |
| opacity: 1; |
| } |
| 50% { |
| transform: translateY(-20px) translateX(10px); |
| opacity: 0.8; |
| } |
| 100% { |
| transform: translateY(0) translateX(0); |
| opacity: 1; |
| } |
| } |
| `; |
| document.head.appendChild(style); |
| |
| |
| createParticles(); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=great1sun/phy" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |