Взаимодействие двух заряженных тел (Закон Кулона) — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
Строка 12: | Строка 12: | ||
*Активное бесконечное построение позволяет следить за телами без остановки, но автоматически меняет начальные параметры в таблицах | *Активное бесконечное построение позволяет следить за телами без остановки, но автоматически меняет начальные параметры в таблицах | ||
*Активная кнопка слежения за телом перемещает его и фиксирует в центре поля, анимация происходит относительно зафиксированного тела | *Активная кнопка слежения за телом перемещает его и фиксирует в центре поля, анимация происходит относительно зафиксированного тела | ||
− | *Обратная | + | *Обратная анимация позволяет совершить перемотку от последнего положения тел до начальных условий |
+ | |||
== Разработка == | == Разработка == | ||
<div class="mw-collapsible mw-collapsed"> | <div class="mw-collapsible mw-collapsed"> |
Версия 11:27, 19 декабря 2016
Виртуальная лаборатория > Динамика взаимодействующих частиц
Управление
Работа с полем
- Возможность перетаскивания тел и рабочего пространства по клику левой кнопкой мыши
- Прорисовка векторов скоростей по клику правой кнопкой мыши
- Приближение к точке колёсиком мыши (отдаление)
- При клике по любому телу во время паузы скорости обоих тел сохраняются в таблицу
Кнопки
- Кнопка "Запустить" - запуск анимации с начальными параметрами, взятыми из таблицы
- Кнопка "Остановить/Продолжить" - пауза и продолжение уже запущенной анимации
- Активное бесконечное построение позволяет следить за телами без остановки, но автоматически меняет начальные параметры в таблицах
- Активная кнопка слежения за телом перемещает его и фиксирует в центре поля, анимация происходит относительно зафиксированного тела
- Обратная анимация позволяет совершить перемотку от последнего положения тел до начальных условий
Разработка
Текст программы на языке JavaScript (разработчик Дрепин Михаил):
Файл "Code.js"
1 window.addEventListener("load", program_code, false);
2 var ctx; //Поле canvas_example
3 var xx1, yy1, xx2, yy2; //координаты тела в данный момент - в статичной прорисовке
4 var koef; //коэфициент масштаба для прорисовки сетки, тел и т.д.
5 var w; //ширина поля
6 var h;//высота поля
7 var vrem=1;//переменная для изменения скорости отрисовки
8 var kx=0, ky=0; //переменная положения мыши для вектора скорости
9 var dx=0, dy=0; //сдвиг поля - обнуляемая переменная
10 var px=0, py=0; //сдвиг поля (по X и по Y)
11 var intervalID; //переменная для функции setInterval (для остановки прорисовки)
12 var Switch=0; //переменная для кнопки - бесконечное/конечное постоение
13 var second_obj=0; //переменная-индикатор слежения за 1 телом ("==1" - активно, "==0" - отключено)
14 var first_obj=0; //переменная-индикатор слежения за 2 телом ("==1" - активно, "==0" - отключено)
15 var idi=0; //переменная для кнопок запустить/пауза/продолжить:
16 /*idi:
17 "==2" - активна прорисовка анимации (нажата "Запустить");
18 "==1" - анимация приостановлена (нажата "Остановить");
19 "==0" - анимация полностью остановлена или не запускалась
20 */
21 var n = 0; //номер активного элемента массива (X/Y/T/V/A)
22 var t = []; //массив "времени"
23 var T=100; //максимальное "время"
24 var a1x = a2x = a1y = a2y = []; //массивы ускорений
25 var vx1 = vx2 = vy1 = vy2 = []; //массивы скоростей
26 var x1 = y1 = x2 = y2 = []; //массивы координат
27 var m1, m2 //масса синего/красного тела
28 var q1, q2, q; //Заряды тел (синего/красного/произведение)
29 const kulkof=8.9875517873681764*3.1; //Н·м2/Кл2 - константа закона Кулона
30 const dt=0.0001; // Шаг времен
31 document.oncontextmenu = function (e) {return false}; //Заблокировать контекстное меню
32 function program_code() { //Часть кода, запускающаяся при загрузке страницы
33 ctx = canvas_example.getContext("2d");
34 w = canvas_example.width;
35 h = canvas_example.height;
36 //параметры для слайдера "Масштаба"
37 Slider_01.value = 20;
38 Slider_01.min = 5;
39 Slider_01.max = 90;
40 Slider_01.step = 1;
41 Text_01.value = Slider_01.value;
42 koef = parseFloat(Slider_01.value);
43 canvas_static_func(); //первоначальная прорисовка
44 time_code(); //включение временного масштаба
45 start.onclick = Start; //клик по кнопке Запустить
46 pauseplay.onclick = PausePlay; //клик по кнопке Остановить/Продолжить
47 telo1.onclick = first_t; //слежение за синим телом
48 telo2.onclick = second_t; //слежение за красным телом
49 switcher.onclick = SwitchForInf; //клик по кнопке "бесконечная прорисовка"
50 returner.onclick = function(){ //Обратная прорисовка
51 if (vrem>0) { //если выключена
52 vrem=-vrem; //включить
53 document.getElementById("returner").innerHTML= "Включить прямую анимацию";
54 if (idi==1&&n!=0) { //если включена пауза
55 document.getElementById("text_u").innerHTML= "Остановить ";
56 animation(); idi=2;
57 }
58 } else if (vrem<0) { //если включена
59 vrem=-vrem; //выключить
60 document.getElementById("returner").innerHTML= "Включить обратную анимацию";
61 }
62 }
63 /*Изменение масштаба колёсиком*/
64 var elem = document.getElementById('canvas_example');
65 if (elem.addEventListener) { //если в окне canvas_example крутится колёсико (для разных браузеров)
66 if ('onwheel' in document) {
67 // IE9+, FF17+
68 elem.addEventListener("wheel", onWheel);
69 } else if ('onmousewheel' in document) {
70 // устаревший вариант события
71 elem.addEventListener("mousewheel", onWheel);
72 } else {
73 // Firefox < 17
74 elem.addEventListener("MozMousePixelScroll", onWheel);
75 }
76 } else { // IE8-
77 elem.attachEvent("onmousewheel", onWheel);
78 }
79 function onWheel(e) {
80 //e = e || window.event;
81 // deltaY, detail содержат пиксели
82 // wheelDelta не дает возможность узнать количество пикселей
83 // onwheel || MozMousePixelScroll || onmousewheel
84 var m = mouseCoords(e); //получаем координаты курсора
85 var delta = e.deltaY || e.detail || e.wheelDelta;
86 var wheel_x=(m.x-20)/koef; //разность координаты по оси X положения курсора мыши и координаты левого края
87 var wheel_y=(h-m.y-20)/koef; //разность координаты по оси Y положения курсора мыши и координаты нижнего края
88 Slider_01.value = Slider_01.value - delta/100; //меняем ползунок слайдера масштаба
89 Text_01.value=Slider_01.value; //меняем численное значение в окне масштаба
90 if (first_obj==0&&second_obj==0) { //если не включено слежение за телами
91 px=px*(koef-delta/100)/koef+m.x-wheel_x*(koef-delta/100)-20;
92 py=py*(koef-delta/100)/koef+m.y-(h-(wheel_y*(koef-delta/100)))+20;
93 /*сдвиги по Х и Y складывается из старого сдвига и сдвига,
94 необходимого для фиксации положения точки с некоторыми координатами,
95 соответствующими положению мыши*/
96 }
97 if (idi!=2) {
98 xx1=(xx1-20)*(koef-delta/100)/koef+20;
99 yy1=h-((h-(yy1+20))*(koef-delta/100)/koef+20);
100 xx2=(xx2-20)*(koef-delta/100)/koef+20;
101 yy2=h-((h-(yy2+20))*(koef-delta/100)/koef+20);
102 canvas_static_func(); // запускаем статичную рисовалку
103 }
104 koef=parseFloat(Slider_01.value); //обновляем коэфициент масштаба
105 e.preventDefault ? e.preventDefault() : (e.returnValue = false); //отменяем прокрутку страницы
106 }
107 Text_01.oninput = function() {
108 if (!this.checkValidity()) return;
109 document.getElementById('Slider_01').value = this.value;
110 app.set_01(this.value);
111 };
112 Slider_01.oninput = function() {
113 document.getElementById('Text_01').value = this.value;
114 app.set_01(this.value);
115 }
116 Text_02.oninput = function() {
117 if (!this.checkValidity()) return;
118 app2.set_02(this.value);
119 document.getElementById('Slider_01').value = this.value;
120 };
121 Slider_02.oninput = function() {
122 app2.set_02(this.value);
123 document.getElementById('Text_02').value = this.value;
124 };
125 if (idi!=2){ //Если не включена прорисовка, то изменение координат в таблице влечёт изменение положения тел на экране
126 iksi.onchange = canvas_static_func;
127 igri.onchange = canvas_static_func;
128 iksii.onchange = canvas_static_func;
129 igrii.onchange = canvas_static_func;
130 }
131 }
132 function SwitchForInf() { //переключатель "бесконечное/конечное постоение"
133 if (Switch==0) {
134 document.getElementById("switch_span").innerHTML= "Выключить бесконечное построение";
135 Switch=1;
136 } else {
137 document.getElementById("switch_span").innerHTML= "Включить бесконечное построение";
138 Switch=0;
139 };
140 }
141 function first_t() { //функция слежения за синим телом
142 if (first_obj==0) { //слеженеие за синим телом не активно
143 first_obj=1; //включить слежение за синим телом
144 second_obj=0; //отключить слежение за красным
145 document.getElementById("text_sl_1").innerHTML= "Прекратить слежение";
146 document.getElementById("text_sl_2").innerHTML= "Следить за красным телом";
147 } else { //слеженеие за синим телом активно
148 first_obj=0; //отключить слежение за синим телом
149 document.getElementById("text_sl_1").innerHTML= "Следить за синим телом";
150 };
151 if (idi!=2&&first_obj==1) { //если не включена анимация
152 px=w/2-xx1; //смещение по X - такое, что 1 тело по центру
153 py=h/2-yy1; //смещение по Y - такое, что 1 тело по центру
154 canvas_static_func(); //нарисовать
155 }
156 }
157 function second_t() { //функция слежения за красным телом
158 if (second_obj==0) { //слеженеие за красным телом не активно
159 second_obj=1; //включить слежение за красным телом
160 first_obj=0; //отключить слежение за синим
161 document.getElementById("text_sl_2").innerHTML= "Прекратить слежение";
162 document.getElementById("text_sl_1").innerHTML= "Следить за синим телом";
163 }
164 else { //слеженеие за красным телом активно
165 second_obj=0; //отключить слежение за красным телом
166 document.getElementById("text_sl_2").innerHTML= "Следить за красным телом";
167 }
168
169 if (idi!=2&&second_obj==1) {
170 px=w/2-xx2;
171 py=h/2-yy2;
172 canvas_static_func();
173 }
174 }
175 function save() { //сохранение активных элементов (участвуют в анимации) массивов в таблицы
176 skor(); //скорости
177 koord(); //координат
178 }
179 function koord() { //сохранение координат
180 iksi.value = Math.round(x1[20*n]*100)/100;
181 igri.value = Math.round(y1[20*n]*100)/100;
182 iksii.value = Math.round(x2[20*n]*100)/100;
183 igrii.value = Math.round(y2[20*n]*100)/100;
184 }
185 function skor () { //сохранение скоростей
186 vxi.value = Math.round(vx1[20*n]*10000)/10000;
187 vyi.value = Math.round(vy1[20*n]*10000)/10000;
188 vxii.value = Math.round(vx2[20*n]*10000)/10000;
189 vyii.value = Math.round(vy2[20*n]*10000)/10000;
190 }
191 function mouseCoords(e) { //функция, определяющая координаты мыши (в пикселях) внутри canvas_example
192 var m = [];
193 var rect = canvas_example.getBoundingClientRect(); //координаты canvas_example относительно окна
194 m.x = e.clientX - rect.left; //координаты курсора в canvas_example по X: положение курсора - расстояние до поля слева
195 m.y = e.clientY - rect.top; //координаты курсора в canvas_example по Y: положение курсора - расстояние до поля сверху
196 return m;
197 }
198 function canvas_static_func() { //прорисовка во время паузы
199 var click; //Идентификатор клика
200 /*click:
201 "==1" - клик ЛКМ по синему телу
202 "==2" - клик ЛКМ по красному телу
203 "==3" - клик ЛКМ по полю
204 "==4" - клик ПКМ по синему телу
205 "==5" - клик ПКМ по красному телу
206 */
207 var vxx1, vxx2, vyy1, vyy2; //координаты скорости при прорисовке векторов
208 var r = 15; //условный радиус обоих тел
209 var xShift, yShift;
210 ctx = canvas_example.getContext("2d");
211 koef = parseFloat(Text_01.value);
212 m1=parseFloat(mi.value); //1а.е.м = 1.6606*10^-27 кг - масса для создания масштаба
213 m2=parseFloat(mii.value); //1а.е.м = 1.6606*10^-27 кг - масса для создания масштаба
214 if (idi!=1) { //если не включена пауза, то при вызове canvas_static_func() сохранить значения из таблицы
215 xx1 = 20+parseFloat(iksi.value)*koef;
216 yy1 = h-(20+parseFloat(igri.value)*koef);
217 xx2 = 20+parseFloat(iksii.value)*koef;
218 yy2 = h-(20+parseFloat(igrii.value)*koef);
219 }
220 if (idi!=2) { //если не включена анимация, то при вызове canvas_static_func() запускать отрисовку
221 draw_static();
222 }
223 this.set_01 = function(input) {
224 var Old_koef=koef; //переменная для сохранения значения koef до его изменения
225 koef=parseFloat(Slider_01.value); //меняем koef
226 if (first_obj==0&&second_obj==0) { //если не включено слежение за телами
227 px=px*koef/Old_koef+w/2-(w/2-20)*koef/Old_koef-20;
228 py=py*koef/Old_koef+h/2-(h-(h/2-20)*koef/Old_koef)+20;
229 /*сдвиги по Х и Y складывается из старого сдвига и сдвига,
230 необходимого для фиксации положения центра*/
231 koef=parseFloat(Slider_01.value); //обновляем коэфициент масштаба
232 }
233 if (idi!=2) {
234 xx1=(xx1-20)*koef/Old_koef+20;
235 yy1=h-((h-(yy1+20))*koef/Old_koef+20);
236 xx2=(xx2-20)*koef/Old_koef+20;
237 yy2=h-((h-(yy2+20))*koef/Old_koef+20);
238 draw_static();
239 }
240 }
241 // функция запускается при нажатии клавиши мыши
242 function draw_static() {
243 koef=parseFloat(Slider_01.value);
244 /*Учитываем условие слежения за синим/красным телом*/
245 if (second_obj==1) {
246 px=w/2-(dx+xx2);
247 py=h/2-(dy+yy2);
248 }
249 if (first_obj==1) {
250 px=w/2-(dx+xx1);
251 py=h/2-(dy+yy1);
252 }
253
254 field(); //нарисовать поле, сетку и расставить числа на осях
255 ctx.beginPath(); //синий шарик
256 ctx.arc(dx+xx1+px, dy+yy1+py, (m1/(m1+m2)+2/3)*koef/4, 0, 2 * Math.PI);
257 ctx.fillStyle="#6666ff";
258 ctx.closePath();
259 ctx.fill();
260
261 ctx.beginPath(); //красный шарик
262 ctx.arc(dx+xx2+px, dy+yy2+py, (m2/(m1+m2)+2/3)*koef/4, 0, 2 * Math.PI);
263 ctx.fillStyle="red";
264 ctx.closePath();
265 ctx.fill();
266
267 /* Прорисовка векторов в визуальном редакторе по ПКМ */
268 if(click==5||click==4) {
269 ctx.beginPath();
270 var xxx1=xx2+px;
271 var xxx2=vxx2+px;
272 var yyy1=yy2+py;
273 var yyy2=vyy2+py;
274 var path=Math.sqrt((xxx2-xxx1)*(xxx2-xxx1)+(yyy2-yyy1)*(yyy2-yyy1)); //длина вектора скорости
275 var x0=xxx1+(1-Math.pow(path,-0.45))*(xxx2-xxx1);
276 var y0=yyy1+(1-Math.pow(path,-0.45))*(yyy2-yyy1);
277 ctx.moveTo(xxx1, yyy1); //начало вектора - координаты тела
278 ctx.lineTo(xxx2, yyy2);
279 ctx.lineTo(x0+(Math.pow(path,0.3))*(yyy2-yyy1)/path, y0-(Math.pow(path,0.3))*(xxx2-xxx1)/path);
280 ctx.lineTo(x0-(Math.pow(path,0.3))*(yyy2-yyy1)/path, y0+(Math.pow(path,0.3))*(xxx2-xxx1)/path);
281 ctx.lineTo(xxx2, yyy2);
282 ctx.closePath();
283 ctx.fillStyle="#000";
284 ctx.fill();
285 ctx.strokeStyle="#000";
286 ctx.stroke();
287 }
288 if(click==4||click==5) {
289 ctx.beginPath();
290 var xxx1=xx1+px;
291 var xxx2=vxx1+px;
292 var yyy1=yy1+py;
293 var yyy2=vyy1+py;
294 var path=Math.sqrt((xxx2-xxx1)*(xxx2-xxx1)+(yyy2-yyy1)*(yyy2-yyy1));
295 var x0=xxx1+(1-Math.pow(path,-0.45))*(xxx2-xxx1);
296 var y0=yyy1+(1-Math.pow(path,-0.45))*(yyy2-yyy1);
297 ctx.moveTo(xxx1, yyy1);
298 ctx.lineTo(xxx2, yyy2);
299 ctx.lineTo(x0+(Math.pow(path,0.3))*(yyy2-yyy1)/path, y0-(Math.pow(path,0.3))*(xxx2-xxx1)/path);
300 ctx.lineTo(x0-(Math.pow(path,0.3))*(yyy2-yyy1)/path, y0+(Math.pow(path,0.3))*(xxx2-xxx1)/path);
301 ctx.lineTo(xxx2, yyy2);
302 ctx.fillStyle="#000";
303 ctx.closePath();
304 ctx.fill();
305 ctx.strokeStyle="#000";
306 ctx.stroke();
307 }
308 }
309 canvas_example.onmousedown = function(e) { // функция запускается при нажатии клавиши мыши
310 var m = mouseCoords(e);
311 var xc1 = xx1+px - m.x;
312 var yc1 = yy1+py - m.y;
313 var rLen1 = xc1 * xc1 + yc1 * yc1;
314 var xc2 = xx2+px - m.x;
315 var yc2 = yy2+py - m.y;
316 var rLen2 = xc2 * xc2 + yc2 * yc2;
317 if (e.which == 1) { //клик ЛКМ
318 if (rLen1 <= r * r) {
319 if (n!==0&&idi!=2) skor(); //Сохранение скорости из массива при клике по телу во время паузы
320 if (rLen1>rLen2) {
321 xShift = xx2 - m.x;
322 yShift = yy2 - m.y;
323 click=2; //Перемещение красного тела
324 canvas_example.onmousemove = mouseMove;
325 } else {
326 xShift = xx1 - m.x;
327 yShift = yy1 - m.y;
328 click=1; //Перемещение синего тела
329 canvas_example.onmousemove = mouseMove;
330 }
331 } else if (rLen2 <= r * r) {
332 if (n!==0&&idi!=2) skor(); //Сохранение скорости из массива при клике по телу во время паузы
333 if (rLen2>rLen1) {
334 xShift = xx1 - m.x;
335 yShift = yy1 - m.y;
336 click=1; //Перемещение синего тела
337 canvas_example.onmousemove = mouseMove;
338 } else {
339 xShift = xx2 - m.x;
340 yShift = yy2 - m.y;
341 click=2; //Перемещение красного тела
342 canvas_example.onmousemove = mouseMove;
343 }
344 }
345 else {
346 click=3; //Клик по полю
347 kx=m.x;
348 ky=m.y;
349 canvas_example.onmousemove = mouseMove;
350 }
351 }
352 if (e.which == 3){ //Клик ПКМ
353 if (rLen1 <= r * r) { //попадание по синему телу
354 if (rLen1>rLen2) { //расстояние до центра красного меньше, чем расстояние дл центра синего
355 click=5; //Изменение вектора скорости красного тела
356 canvas_example.onmousemove = mouseMove;
357 } else {
358 click=4; //Изменение вектора скорости синего тела
359 canvas_example.onmousemove = mouseMove;
360 }
361 }
362 else if (rLen2 <= r * r) { //попадание по красному телу
363 if (rLen2>rLen1) { //расстояние до центра синего меньше, чем расстояние дл центра красного
364 click=4; //Изменение вектора скорости синего тела
365 canvas_example.onmousemove = mouseMove;
366 } else {
367 click=5; //Изменение вектора скорости красного тела
368 canvas_example.onmousemove = mouseMove;
369 }
370 }
371 }
372 };
373 canvas_example.onmouseup = function() {
374 if (click==3) {
375 px=px+dx;
376 py=py+dy;
377 kx=ky=dx=dy=0;
378 }
379 canvas_example.onmousemove = null;
380 };
381 function mouseMove(e) {
382 var m = mouseCoords(e);
383 if (idi!=2) {
384 if (click==1) {
385 xx1 = m.x + xShift;
386 yy1 = m.y + yShift;
387 iksi.value = (xx1-20)/koef;
388 igri.value = (h-(yy1+20))/koef;
389 draw_static();
390 };
391 if (click==2) {
392 xx2 = m.x + xShift;
393 yy2 = m.y + yShift;
394 iksii.value = (xx2-20)/koef;
395 igrii.value = (h-(yy2+20))/koef;
396 draw_static();
397 };
398 }
399 if (click==3) {
400 dx=m.x-kx;
401 dy=m.y-ky;
402 if (idi!=2) draw_static();
403 };
404 if (idi!=2) {
405 if (click==4) {
406 vxx1 = m.x-px;
407 vyy1 = m.y-py;
408 vxi.value = (vxx1-xx1)/koef;
409 vyi.value = (yy1-vyy1)/koef;
410 iksi.value = (xx1-20)/koef;
411 igri.value = (h-(yy1+20))/koef;
412 iksii.value = (xx2-20)/koef;
413 igrii.value = (h-(yy2+20))/koef;
414 draw_static();
415 };
416 if (click==5) {
417 vxx2 = m.x-px;
418 vyy2 = m.y-py;
419 vxii.value = (vxx2-xx2)/koef;
420 vyii.value = (yy2-vyy2)/koef;
421 iksi.value = (xx1-20)/koef;
422 igri.value = (h-(yy1+20))/koef;
423 iksii.value = (xx2-20)/koef;
424 igrii.value = (h-(yy2+20))/koef;
425 draw_static();
426 };
427 };
428 };
429 }
430 function time_code() { //временной масштаб
431 Slider_02.min = 1;
432 Slider_02.max = 90;
433 Slider_02.step = 1;
434 Slider_02.value = 1;
435 Text_02.value = Slider_02.value;
436 this.set_02 = function(input) { //запуск при изменении значения set_02
437 vrem=Math.sign(vrem)*parseFloat(Slider_02.value); //изменение переменной скорости отрисовки
438 }
439 }
440 function Start() { //Старт по кнопке "Запустить"
441 buttonStart(); //функция, сообщающая, что старт совершён по кнопке "Запустить": порядок прорисовки прямой, с нулевого элемента
442 animation(); //запуск анимации
443 }
444 function buttonStart() { //Изменение значений кнопок и идентификатора idi
445 document.getElementById("returner").innerHTML= "Включить обратную анимацию";
446 document.getElementById("text_u").innerHTML= "Остановить ";
447 idi=2;
448 }
449 function PausePlay() { //Кнопка "Остановить/Продолжить"
450 if (idi!=1) { //Если пауза не включена
451 clearInterval(intervalID); //остановить прорисовку
452 document.getElementById("text_u").innerHTML= "Продолжить";
453 idi=1; //активировать паузу
454 }
455 else { //иначе
456 if (n!==0) { //если уже была включена анимация, следовательно кнопка нажата во время паузы
457 document.getElementById("text_u").innerHTML= "Остановить "; animation(); idi=2; //запустить прорисовку
458 };
459 if (n==0) { //если анимация не включалась
460 document.getElementById("text_u").innerHTML= "Остановить "; idi=0;
461 }
462 }
463 }
464 function animation(){ //анимация движения частиц
465 clearInterval(intervalID); //обнулять старый интервал при каждом новом запуске анимации
466 koef=parseFloat(Slider_01.value);
467 function A(a1,a2,b1,b2,q,m) { //рассчёт ускорения тела из условия взаимного притяжения/отталкивания двух тел по закону Кулона
468 var r=Math.sqrt((a2-a1)*(a2-a1)+(b2-b1)*(b2-b1));
469 return (-1)*kulkof*q*(a2-a1)/(m*r*r*r)
470 };
471 if (idi==2) { //если система запущена по кнопке "Запустить"
472 physics(); //сосчитать массивы координат и скоростей
473 n=0; //обнулить переменную, пробегающую массивы
474 }
475 function physics() {
476 vrem=Math.abs(vrem);
477 t = [];
478 a1x = []; a2x = []; a1y = []; a2y = [];
479 vx1 = []; vx2 = []; vy1 = []; vy2 = [];
480 x1 = []; y1 = []; x2 = []; y2 = [];
481 t[0]=0;
482 x1[0]=parseFloat(iksi.value);
483 y1[0]=parseFloat(igri.value);
484 x2[0]=parseFloat(iksii.value);
485 y2[0]=parseFloat(igrii.value);
486 vx1[0]=parseFloat(vxi.value);
487 vy1[0]=parseFloat(vyi.value);
488 vx2[0]=parseFloat(vxii.value);
489 vy2[0]=parseFloat(vyii.value);
490 m1=parseFloat(mi.value);
491 m2=parseFloat(mii.value);
492 q1=parseFloat(qi.value);
493 q2=parseFloat(qii.value);
494 q=q1*q2;
495 a1x[0]= A(x1[0],x2[0],y1[0],y2[0],q,m1);
496 a1y[0]= A(y1[0],y2[0],x1[0],x2[0],q,m1);
497 a2x[0]= A(x2[0],x1[0],y1[0],y2[0],q,m2);
498 a2y[0]= A(y2[0],y1[0],x1[0],x2[0],q,m2);
499 var i=0;
500 while (t[i] < T) {
501 vx1[i+1]= vx1[i]+a1x[i]*dt;
502 vy1[i+1]= vy1[i]+a1y[i]*dt;
503 vx2[i+1]= vx2[i]+a2x[i]*dt;
504 vy2[i+1]= vy2[i]+a2y[i]*dt;
505
506 x1[i+1] = x1[i]+vx1[i+1]*dt;
507 y1[i+1] = y1[i]+vy1[i+1]*dt;
508 x2[i+1] = x2[i]+vx2[i+1]*dt;
509 y2[i+1] = y2[i]+vy2[i+1]*dt;
510
511 a1x[i+1]= A(x1[i+1],x2[i+1],y1[i+1],y2[i+1],q,m1);
512 a1y[i+1]= A(y1[i+1],y2[i+1],x1[i+1],x2[i+1],q,m1);
513 a2x[i+1]= A(x2[i+1],x1[i+1],y1[i+1],y2[i+1],q,m2);
514 a2y[i+1]= A(y2[i+1],y1[i+1],x1[i+1],x2[i+1],q,m2);
515 t[i+1]=t[i]+dt;
516 i=i+1;
517 }
518 }
519 function draw_dinamic() {
520 field(); //Прорисовка поля
521 /*Учитываем условие слежения за синим/красным телом*/
522 if (second_obj==1) {
523 px=w/2-(dx+20+x2[20*n]*koef);
524 py=-h/2-(dy-(20+y2[20*n]*koef));
525 }
526 if (first_obj==1) {
527 px=w/2-(dx+20+x1[20*n]*koef);
528 py=-h/2-(dy-(20+y1[20*n]*koef));
529 }
530 ctx.beginPath(); //рисуем синее тело
531 ctx.arc(px+dx+20+x1[20*n]*koef,py+dy+h-(20+y1[20*n]*koef), 1/4*(m1/(m1+m2)+2/3)*koef, 0, Math.PI*2);
532 ctx.fillStyle = "#6666ff";
533 ctx.closePath();
534 ctx.fill();
535
536 ctx.beginPath(); //рисуем красное тело
537 ctx.arc(px+dx+20+x2[20*n]*koef,py+dy+h-(20+y2[20*n]*koef), 5*(m2/(m1+m2)+2/3)*koef/20, 0, Math.PI*2);
538 ctx.fillStyle = "red";
539 ctx.closePath();
540 ctx.fill();
541
542 xx1=20+x1[20*n]*koef; yy1=h-(20+y1[20*n]*koef); //положение синего тела сохраняем для визуального редактирования
543 xx2=20+x2[20*n]*koef; yy2=h-(20+y2[20*n]*koef); //положение красного тела сохраняем для визуального редактирования
544 n=n+vrem;
545 }
546 function control() {
547 draw_dinamic();
548 if(n>=(t.length/20-vrem)){
549 n=n-vrem; //возвращаем n к значению, соответствующему одному из последних существующих элементов массива
550 if (Switch==1) { //Если включено бексконечное построение
551 save(); //Сохранять последнее значение координат и скоростей
552 idi=2; //Инициировать запуск системы по кнопке
553 animation(); //И запускать прорисовку с новыми элементами массивов
554 } else if (Switch==0) { //Если выключено бексконечное построение
555 clearInterval(intervalID); //остановить прорисовку
556 draw_dinamic(); //Нарисовать положение в последний момент
557 idi=0; //Инициировать остановку анимации
558 }
559 }
560 if (n<0) { //Если перемотка привела к началу массивов/начальному положению системы тел
561 clearInterval(intervalID); //остановить прорисовку
562 n=0; //Вернуться к начальным условиям
563 vrem=-vrem; //нормальный ход времени
564 draw_dinamic(); //Нарисовать тела
565 idi=0; //Инициировать остановку анимации
566 }
567 }
568 intervalID=setInterval(control,1); //Выполнение "control", обеспечивающего прорисовку анимации, через 1 миллисекунду
569 }
570 function field() { //Функция прорисовки поля
571 ctx.clearRect(0, 0, w, h);
572 ctx.fillStyle = 'white';
573 ctx.fillRect(20, 20, w-40, h-40);
574 ctx.strokeStyle = 'black';
575 ctx.strokeRect(20, 20, w-40, h-40);
576 ctx.fillStyle = 'black';
577 ctx.font = "bold italic 20px Times";
578 ctx.fillText("x", w-15, h - 20);
579 ctx.fillText("y", 15, 15);
580 ctx.font = "italic 16px Times";
581 ctx.fillText(0, 1.5, h - 4.5);
582 /*Сетка*/
583 for (var k = dx+px+20+koef; k < w-20; k = k+koef) {
584 ctx.beginPath();
585 if (k>20) {
586 ctx.moveTo(k,h-20);
587 ctx.lineTo(k,20);
588 ctx.strokeStyle = "#cab0b0";
589 ctx.closePath();
590 ctx.stroke();
591 }
592 }
593 for (var k = dx+px+20; (k > 0); k = k-koef) {
594 ctx.beginPath();
595 if (k>20&&k<w-20) {
596 ctx.moveTo(k,h-20);
597 ctx.lineTo(k,20);
598 ctx.strokeStyle = "#cab0b0";
599 ctx.closePath();
600 ctx.stroke();
601 }
602 }
603 for (var u = dy+h+py-20-koef; u >20 ; u = u-koef) {
604 ctx.beginPath();
605 if (u<h-20) {
606 ctx.strokeStyle = "#cab0b0";
607 ctx.moveTo(20, u);
608 ctx.lineTo(w-20, u);
609 ctx.closePath();
610 ctx.stroke();
611 }
612 }
613 for (var u = dy+h+py-20; u < h ; u = u+koef) {
614 ctx.beginPath();
615 if (u<h-20&&u>20) {
616 ctx.strokeStyle = "#cab0b0";
617 ctx.moveTo(20, u);
618 ctx.lineTo(w-20, u);
619 ctx.closePath();
620 ctx.stroke();
621 }
622 }
623 /* "+5" нумерация */
624 if (koef<20) {
625 for (var oy = dy+py+h-15-5*koef, ooy=5; oy>20; oy=oy-5*koef) {
626 ctx.fillStyle = 'black';
627 ctx.font = "italic 16px Times";
628 if (oy<h-20) {
629 ctx.fillText(ooy, 1.5, oy);
630 }
631 ooy+=5;
632 }
633 for (var oy = dy+h+py-15, ooy=0; oy<h; oy=oy+5*koef) {
634 ctx.fillStyle = 'black';
635 ctx.font = "italic 16px Times";
636 if (oy<h-20&&oy>20) {
637 ctx.fillText(ooy, 1.5, oy);
638 }
639 ooy-=5;
640 }
641 for (var ox = dx+px+15.5+5*koef, oox=5; ox<w-20; ox=ox+5*koef) {
642 ctx.fillStyle = 'black';
643 ctx.font = "italic 16px Times";
644 if (ox>20) {
645 ctx.fillText(oox, ox, h-2);
646 }
647 oox+=5;
648 }
649 for (var ox = dx+px+15.5, oox=0; ox>0; ox=ox-5*koef) {
650 ctx.fillStyle = 'black';
651 ctx.font = "italic 16px Times";
652 if (ox>20&&ox<w-20) {
653 ctx.fillText(oox, ox, h-2);
654 }
655 oox-=5;
656 }
657 }
658 /* Простая нумерация */
659 else {
660 for (var oy = dy+h+py-15-koef, ooy=1; oy>20; oy=oy-koef) {
661 ctx.fillStyle = 'black';
662 ctx.font = "italic 16px Times";
663 if (oy<h-20) {
664 ctx.fillText(ooy, 1.5, oy);
665 }
666 ooy++;
667 }
668 for (var ox = dx+px+15.5+koef, oox=1; ox<w-20; ox=ox+koef) {
669 ctx.fillStyle = 'black';
670 ctx.font = "italic 16px Times";
671 if (ox>20) {
672 ctx.fillText(oox, ox, h-2);
673 }
674 oox++;
675 if (oox>100) { //После X=100 единицы масштаба наносятся через 5 клеток
676 ox=ox+4*koef;
677 oox=oox+4;
678 }
679 }
680 for (var oy = dy+h+py-15, ooy=0; oy<h; oy=oy+koef) {
681 ctx.fillStyle = 'black';
682 ctx.font = "italic 16px Times";
683 if (oy<h-20&&oy>20) {
684 ctx.fillText(ooy, 1.5, oy);
685 }
686 ooy--;
687 }
688 for (var ox = dx+px+15.5, oox=0; ox>0; ox=ox-koef) {
689 ctx.fillStyle = 'black';
690 ctx.font = "italic 16px Times";
691 if (ox>20&&ox<w-20) {
692 ctx.fillText(oox, ox, h-2);
693 }
694 oox--;
695 if (oox<-10) { //До X=-10 единицы масштаба наносятся через 5 клеток
696 ox=ox-4*koef;
697 oox=oox-4;
698 }
699 }
700 }
701 }
Файл "culon.html"
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <script src="Code.js"></script>
6 <script src="bg.js"></script>
7 <link rel="stylesheet" type="text/css" href="style.css" />
8 <title>Взаимодействие двух заряженных тел (Закон Кулона)</title>
9 </head>
10 <body>
11 <canvas id="canvas_bg" class="canvas_bg"></canvas>
12 <div class="main" id="main">
13 <div style="float:left; margin-left: 20px;"> Масштаб:
14 <I>1 м.</I> = <input id="Text_01" style="width: 2.2ex;" required pattern="[-+]?([0-9]*\.[0-9]+|[0-9]+)" > пкс.
15 <input type="range" id="Slider_01" style="width: 100px;" value="20">
16 </div>
17 <div id="workspace" style="float:right; margin-right: 20px;"><canvas id="canvas_example" class="canvas_example" width="750" height="550"></canvas>
18 </div>
19 <div style="float:left; text-align: center; margin-left: 20px;">
20 <p>FPS:<input id="Text_02" style="width: 2.2ex;" required pattern="[-+]?([0-9]*\.[0-9]+|[0-9]+)">
21 <input type="range" id="Slider_02" style="width: 100px;">
22 </p><br />
23 <a href="#" id=start class="button">Запустить</a>
24 <a href="#" id=pauseplay class="button"><SPAN id=text_u>Остановить </SPAN></a><br>
25 <a href="#" id=linka class="button28" onclick="save(); canvas_static_func()">
26 Сохранить координаты и скорость тел<br>для последующего запуска</a> <br>
27 <h2>Синее тело</h2>
28 <table>
29 <tbody>
30 <tr><th colspan="5">Координаты тела</th></tr>
31 <tr><td><I>X: </I><input id=iksi type=number value=18></td>
32 <td><I> Y: </I><input id=igri type=number value=12.71></td></tr>
33 <tr><th colspan="5">Проекции скорости</th></tr>
34 <tr><td><I>На OX: </I><input id=vxi type=number value=0></td>
35 <td><I> на OY: </I><input id=vyi type=number value=0></td></tr>
36 <tr><th colspan="5">Масса и заряд</th></tr>
37 <tr><td><input id=mi type=number value=1670><I>x 10<sup>-30</sup>кг</I></td>
38 <td><input id=qi type=number value=1><I> x 10<sup>-19</sup>Кл</I></td></tr>
39 </tbody>
40 </table>
41 <h2>Красное тело</h2>
42 <table>
43 <tbody>
44 <tr><th colspan="5">Координаты тела</th></tr>
45 <tr><td><I>X: </I><input id=iksii type=number value=18></td>
46 <td><I> Y: </I><input id=igrii type=number value=18.29></td></tr>
47 <tr><th colspan="5">Проекции скорости</th></tr>
48 <tr><td><I>X:</I><input id=vxii type=number value=2.22><I>x 10<sup>6</sup></I><sub>с</sub><sup>м</sup></td>
49 <td><I>Y:</I><input id=vyii type=number value=0><I>x 10<sup>6</sup></I><sub>с</sub><sup>м</sup></td></tr>
50 <tr><th colspan="5">Масса и заряд</th></tr>
51 <tr><td><input id=mii type=number value=0.91><I>x 10<sup>-30</sup>кг</I></td>
52 <td><input id=qii type=number value=-1><I>x 10<sup>-19</sup>Кл</I></td></tr>
53 </tbody>
54 </table>
55 </div>
56 <div class="follow" style="float: left" >
57 <a style="background: #6666ff!important;" href="#" id=telo1 class="button28"><SPAN id=text_sl_1>Следить за синим телом</span></a>
58 <a style="background: red!important;" href="#" id=telo2 class="button28"><SPAN id=text_sl_2>Следить за красным телом</span></a>
59 <a href="#" id=switcher class="button28"><SPAN id=switch_span>Включить бесконечное построение</span></a>
60 <a href="#" id=returner class="button28"><SPAN id=switch_span>Включить обратную анимацию</span></a>
61 </div>
62 </div>
63 <script type="text/javascript">
64 var app = new canvas_static_func(document.getElementById('canvas_example'));
65 var app2 = new time_code(document.getElementById('canvas_example'));
66 </script>
67 </body>
68 </html>
Файл "bg.js"
1 window.addEventListener("load", program_code, false);
2 function program_code() {
3 var canvas = document.getElementById('canvas_bg')[0],
4 ctx = null,
5 grad = null,
6 body = document.getElementsByTagName('body')[0],
7 color = 255; //изначальный цвет фона сайта
8
9 if (canvas_bg.getContext('2d')) {
10 ctx = canvas_bg.getContext('2d');
11 ctx.clearRect(0, 0, 600, 600);
12 ctx.save();
13
14 // создание радиального градиента
15 grad = ctx.createRadialGradient(0,0,0,0,0,600);
16 grad.addColorStop(0, '#DFDFDF');
17 grad.addColorStop(1, 'rgb(' + color + ', ' + color + ', ' + color + ')');
18
19 // сам фон-градиент
20 ctx.fillStyle = grad;
21
22 first_time(); //при первом запуске
23 function first_time() {
24 var width = window.innerWidth,
25 height = window.innerHeight,
26 x = width/2,
27 y = height/2,
28 rx = 600 * x / width,
29 ry = 600 * y / height;
30
31 var xc = ~~(256 * x / width);
32 var yc = ~~(256 * y / height);
33
34 grad = ctx.createRadialGradient(rx, ry, 0, rx, ry, 500); //размер указателя мышки
35 grad.addColorStop(0, '#478CFB'); //цвет указателя мышки
36 grad.addColorStop(1, ['rgb(', xc, ', ', (255 - xc), ', ', yc, ')'].join(''));
37 ctx.fillStyle = grad;
38 ctx.fillRect(0,0,600,600);
39 };
40
41 body.onmousemove = function (event) {
42 var width = window.innerWidth,
43 height = window.innerHeight,
44 x = event.clientX,
45 y = event.clientY,
46 rx = 600 * x / width,
47 ry = 600 * y / height;
48 var xc = ~~(256 * x / width);
49 var yc = ~~(256 * y / height);
50
51 grad = ctx.createRadialGradient(rx, ry, 0, rx, ry, 500); //размер указателя мышки
52 grad.addColorStop(0, '#478CFB'); //цвет указателя мышки
53 grad.addColorStop(1, ['rgb(', xc, ', ', (255 - xc), ', ', yc, ')'].join(''));
54 //ctx.restore();
55 ctx.fillStyle = grad;
56 ctx.fillRect(0,0,600,600);
57 // ctx.save();
58 };
59 }
60 }
Файл "style.css"
1 h2, h1 {
2 margin: 10px 0 0 0;
3 color: #fff;
4 text-shadow: 1px 1px 1px black, 0 0 0.1em blue;;
5 }
6 .button {
7 font-size: 18px;
8 font-weight: 700;
9 color: white;
10 text-decoration: none;
11 padding: .4em 1em calc(.4em + 3px);
12 border-radius: 3px;
13 background: rgb(64,199,129);
14 box-shadow: 0 -3px rgb(53,167,110) inset;
15 transition: 0.2s;
16 }
17 .button:hover { background: rgb(53, 167, 110); }
18 .button:active {
19 background: rgb(33,147,90);
20 box-shadow: 0 3px rgb(33,147,90) inset;
21 }
22 a.button28 {
23 position: relative;
24 display: inline-block;
25 font-size: 90%;
26 font-weight: 700;
27 color: rgb(209,209,217);
28 text-decoration: none;
29 text-shadow: 0 -1px 2px rgba(0,0,0,.2);
30 padding: .5em 1em;
31 outline: none;
32 border-radius: 3px;
33 background: linear-gradient(rgb(110,112,120), rgb(81,81,86)) rgb(110,112,120);
34 box-shadow:
35 0 1px rgba(255,255,255,.2) inset,
36 0 3px 5px rgba(0,1,6,.5),
37 0 0 1px 1px rgba(0,1,6,.2);
38 transition: .2s ease-in-out;
39 margin-top: 10px;
40 }
41 a.button28:hover:not(:active) {
42 background: linear-gradient(rgb(126,126,134), rgb(70,71,76)) rgb(126,126,134);
43 }
44 a.button28:active {
45 top: 1px;
46 background: linear-gradient(rgb(76,77,82), rgb(56,57,62)) rgb(76,77,82);
47 box-shadow:
48 0 0 1px rgba(0,0,0,.5) inset,
49 0 2px 3px rgba(0,0,0,.5) inset,
50 0 1px 1px rgba(255,255,255,.1);
51 }
52 input[type="number"] {
53 border: 1px solid black;
54 border-radius: 5px;
55
56 color: #000000;
57 padding: 3px;
58 margin-top: 2px;
59 margin-bottom: 2px;
60 font-size: 16px;
61 font-family: Verdana;
62 background: #FFF;
63 width: 70px;
64 }
65 input[type="number"]:focus {
66 color: #000000;
67 border: 1px solid #000000
68 }
69 canvas.canvas_bg {
70 position: absolute; /* позиционирование */
71 top: 0; /* фиксируем */
72 left: 0; /* фиксируем */
73 height: 100%; /* делаем фон резиновым */
74 width: 100%; /* делаем фон резиновым */
75 }
76
77
78 div.main {
79 position: absolute;
80 top:0;
81 left:0;
82 /*width:100%;
83 height:100%;*/
84 }
85 sub + sup {
86 margin-left: -0.4em;
87 }
88
89 /*Таблица*/
90 table {
91 border-spacing: 0;
92 text-align: center;
93 border-top-right-radius: 10px;
94 border-top-left-radius: 10px;
95 }
96 th {
97 background: rgba(101, 11, 95, 0.86);
98 color: white;
99 text-shadow: 0 1px 1px #2D2020;
100 padding: 0px;
101 }
102 th, td {
103 colspan: 5;
104 border-style: solid;
105 border-width: 0 1px 1px 0;
106 border-color: white;
107 }
108 th:first-child, td:first-child {
109 text-align: center;
110 }
111 th:first-child {
112 }
113 th:last-child {
114
115 border-right: none;
116 }
117 td {
118 padding: 1px 2px;
119 background: #ecfc95;
120 }
121 tr:last-child td:first-child {
122 border-radius: 0 0 0 10px;
123 }
124 tr:last-child td:last-child {
125 border-radius: 0 0 10px 0;
126 }
127 tr td:last-child {
128 border-right: none;
129 }
130 p{
131 margin:0;
132 }
133
134 .follow {
135 margin-left: 150px;
136 }
Совместный проект студентов Дрепина Михаила и Калинина Ильи