So, we have a mathematical pendulum. Help to realize that after launching the program it was possible to manually (with the mouse) lift the ball and release it to oscillate Ps Or you can also use CSS or JavaScript

<html> <body> <style> * { padding: 0; margin: 0; } canvas {display: block; margin: 0 auto; } </style> <canvas id="canvas"></canvas> <canvas id="canvas2" style="background: #eee"></canvas> </body> <script> var canvas = document.getElementById("canvas") var canvas2 = document.getElementById("canvas2") var ctx = canvas.getContext("2d") var ctx2 = canvas2.getContext("2d") var h = canvas.height = 500 var w = canvas.width = 600 var h2 = canvas2.height = 300 var w2 = canvas2.width = 800 ctx.translate(w/2,h/2) ctx2.translate(0,h2/2) ctx2.beginPath() ctx2.moveTo(0,0) var initPhi = Math.PI*0.2 var L = 200 var dt = 1/60 var g = 1500 var t = 0 bob = { phi: initPhi, v: 0, a: 0 } function drawPendulum(){ ctx.beginPath() ctx.arc(Math.sin(bob.phi)*L,Math.cos(bob.phi)*L,10,0,2*Math.PI) ctx.fill() ctx.moveTo(0,0) ctx.lineTo(Math.sin(bob.phi)*L,Math.cos(bob.phi)*L) ctx.stroke() } function update(){ bob.a = -(g/L)*Math.sin(bob.phi) bob.v += bob.a*dt bob.phi += bob.v*dt t += dt } function drawGraph(){ ctx2.lineTo(t*20,(bob.phi%Math.PI)*20 ) ctx2.stroke() } function draw(){ ctx.clearRect(-w/2,-h/2,w,h) drawPendulum() update() drawGraph() requestAnimationFrame(draw) } draw() </script> </html> 

1 answer 1

Everything is, in fact, quite simple. There are several things to do:

  • define handler for clicking on the left mouse button (LMB)
  • define handler for unplugging
  • define a mouse movement handler

In the handler for pressing the LMB, you need to change the mode (draggin <- true) and save the current position of the center of the canvas (relative to which the pendulum is drawn) and the direction angle from the center of the canvas to the position of the mouse cursor, as well as the current angle of rotation of the pendulum.

In the handler for depressing the LMB, you need to change the mode (draggin <- false) and reset the current speed and acceleration so as not to break the physics of the process.

In the mouse movement handler, you need to understand what mode we are in now (if draggin === true , then you need to handle the movement).

During motion processing, a new direction angle to the cursor is calculated and the difference between the current and initial direction angles is subtracted from the saved position of the pendulum.

You also need to remember to forbid recalculating mechanics when moving the starting point.

My version of the code with comments is given below:

 var canvas = document.getElementById("canvas"); var canvas2 = document.getElementById("canvas2"); var ctx = canvas.getContext("2d"); var ctx2 = canvas2.getContext("2d"); var h = canvas.height = 500; var w = canvas.width = 600; var h2 = canvas2.height = 300; var w2 = canvas2.width = 800; var draggin = false; // Π’ Ρ€Π΅ΠΆΠΈΠΌΠ΅ пСрСмСщСния var dragX = 0; // Π¦Π΅Π½Ρ‚Ρ€ канваса, ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π±ΡƒΠ΄Π΅ΠΌ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ var dragY = 0; var dragPhi = 0; // Π£Π³ΠΎΠ» маятника ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ var dragKsy = 0; // ΠΠ°Ρ‡Π°Π»ΡŒΠ½Ρ‹ΠΉ ΡƒΠ³ΠΎΠ» ΠΏΡ€ΠΈ mousedown ctx.translate(w / 2, h / 2); ctx2.translate(0, h2 / 2); ctx2.beginPath(); ctx2.moveTo(0, 0); var initPhi = Math.PI * 0.2; var L = 200; var dt = 1 / 60; var g = 1500; var t = 0; bob = { phi: initPhi, v: 0, a: 0 }; //getPos - ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Ρ†Π΅Π½Ρ‚Ρ€Π° элСмСнта function getPos(el) { var rect = el.getBoundingClientRect(); return { x: rect.left + rect.width / 2.0, y: rect.top + rect.height / 2.0 }; } // ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ ΡƒΠ³ΠΎΠ» ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚Π° ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Ρ†Π΅Π½Ρ‚Ρ€Π° канваса function calcKsy(evt) { var deltaX = evt.clientX - dragX; var deltaY = evt.clientY - dragY; var Ksy = Math.atan2(deltaY, deltaX); return Ksy; } // ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ событиС наТатия Π½Π° Π»Π΅Π²ΡƒΡŽ ΠΊΠ½ΠΎΠΏΠΊΡƒ ΠΌΡ‹ΡˆΠΈ canvas.addEventListener("mousedown", function(evt) { var gpc = getPos(canvas); dragX = gpc.x; dragY = gpc.y; draggin = true; dragPhi = bob.phi; dragKsy = calcKsy(evt); }); // ΠŸΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ маятник Π½Π° ΡƒΠ³ΠΎΠ» ΠΌΠ΅ΠΆΠ΄Ρƒ Π½Π°Ρ‡Π°Π»ΡŒΠ½Ρ‹ΠΌ ΡƒΠ³Π»ΠΎΠΌ ΠΏΡ€ΠΈ mousedown // ΠΈ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΌ послС пСрСмСщСния курсора canvas.addEventListener("mousemove", function(evt) { if(draggin){ var Ksy = calcKsy(evt); bob.phi = dragPhi - Ksy + dragKsy; } }); // ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ событиС отТатия Π»Π΅Π²ΠΎΠΉ ΠΊΠ½ΠΎΠΏΠΊΠΈ ΠΌΡ‹ΡˆΠΈ canvas.addEventListener("mouseup", function(evt) { draggin = false; bob.v = 0; bob.a = 0; }); function drawPendulum() { ctx.beginPath() ctx.arc(Math.sin(bob.phi) * L, Math.cos(bob.phi) * L, 10, 0, 2 * Math.PI) ctx.fill() ctx.moveTo(0, 0) ctx.lineTo(Math.sin(bob.phi) * L, Math.cos(bob.phi) * L) ctx.stroke() } function update() { bob.a = -(g / L) * Math.sin(bob.phi) bob.v += bob.a * dt bob.phi += bob.v * dt t += dt } function drawGraph() { ctx2.lineTo(t * 20, (bob.phi % Math.PI) * 20) ctx2.stroke() } function draw() { ctx.clearRect(-w / 2, -h / 2, w, h) drawPendulum() // Если ΠΌΡ‹ Π½Π΅ Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ пСрСтаскивания, Ρ‚ΠΎ ΠΊΠ°Ρ‡Π°Π΅ΠΌ маятник if (draggin === false) { update() } drawGraph() requestAnimationFrame(draw) } draw() 
 * { padding: 0; margin: 0; } canvas { display: block; margin: 0 auto; cursor: move; cursor: grab; cursor: -moz-grab; cursor: -webkit-grab; } 
 <canvas id="canvas"></canvas> <canvas id="canvas2" style="background: #eee"></canvas>