Математический маятник с шаром

121
25 июля 2019, 07:00

Итак, у нас есть математический маятник. Помогите реализовать, чтобы после запуска программы можно было в ручную (мышкой) поднять шар и отпустить для колебания P.s. Либо можно еще CSS или 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>

Answer 1

Все, на самом деле, достаточно просто. Нужно сделать несколько вещей:

  • определить обработчик нажатия на левую кнопку мыши (ЛКМ)
  • определить обработчик отжатия ЛКМ
  • определить обработчик перемещения мыши

В обработчике нажатия ЛКМ нужно поменять режим (draggin <- true) и сохранить текущее положение центра канваса (относительно которого рисуется маятник) и угол направления от центра канваса на положение курсора мыши, а так же текущий угол поворота маятника.

В обработчике отжатия ЛКМ нужно поменять режим (draggin <- false) и обнулить текущую скорость и ускорение - чтобы не поломать физику процесса.

В обработчике перемещения мыши нужно понять в каком режиме мы сейчас находимся (если draggin === true - то нужно обрабатывать перемещение).

При обработке перемещения вычисляется новый угол направления на курсор и разница между текущим и начальным углами направления вычитается из сохраненного положения маятника.

Так же нужно не забыть запрещать пересчитывать механику при перемещении начальной точки.

Мой вариант кода с коментариями приведен ниже:

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>

READ ALSO
Frontend. Как реализовать блок? [закрыт]

Frontend. Как реализовать блок? [закрыт]

Нужно чтобы при нажатии на цифры, выделенные красным, менялся контент, выделенный зеленымТолько начинаю свой путь в верстке, подскажите с помощью...

149
c# как отправить текст в Яндекс.Алиса?

c# как отправить текст в Яндекс.Алиса?

Задумал написать расширение для twitch бота - общение с Алисой в текстовом виде

153
Нужен async/await или не нужен?

Нужен async/await или не нужен?

Изучаю асинхронное программирование и вижу следующий метод

105