index.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <link rel="manifest" href="/site.webmanifest">
  5. <!-- <link async rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
  6. integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous"> -->
  7. <link rel="stylesheet" href="../css/bootstrap.min.css"
  8. integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
  9. <link rel="stylesheet" href="../css/style.css">
  10. <link rel="preconnect" href="https://fonts.gstatic.com">
  11. <link href="https://fonts.loli.net/css2?family=Anonymous+Pro:ital,wght@0,400;0,700;1,400;1,700
  12. &family=Noto+Serif+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
  13. <script src="https://apps.bdimg.com/libs/jquery/1.10.2/jquery.min.js"></script>
  14. <meta charset="UTF-8">
  15. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  16. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  17. <title>Gravity</title>
  18. <style>
  19. * {
  20. margin: 0;
  21. padding: 0;
  22. width: 100%;
  23. height: 100%;
  24. overflow: hidden;
  25. }
  26. .btn {
  27. width: auto;
  28. height: auto;
  29. }
  30. body {
  31. background: radial-gradient(rgb(235, 235, 235), floralwhite);
  32. padding: 0;
  33. }
  34. </style>
  35. </head>
  36. <body>
  37. <a class="btn btn-default" href="/" onmouseenter="alert('单击屏幕添加元素。\n所有元素互相吸引,鼠标亦有引力。');$('.btn').hide()"
  38. style="position:fixed"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span></a>
  39. <canvas id="canvas" onclick='init(10)' width="500" height="500"></canvas>
  40. </body>
  41. <script>
  42. const LOST = 0.3;
  43. var canvas = document.getElementById('canvas');
  44. var context = canvas.getContext('2d');
  45. var planets = [];
  46. const MAX_MASS = 3000;
  47. const PLANET_COUNT = 300;
  48. const FRAGMENT_COUNT = 100;
  49. const FRAGMENT_SPEED = 20;
  50. const MAX_SPEED = 8;
  51. const G = 0.5;
  52. var maxLineLength = 45;
  53. const DEFAULT_MASS = 20;
  54. const LOCK_TIME = 50;
  55. const COLOR = '#333';
  56. const LINE_COLOR = '#2344';
  57. const MOUSE_MASS = 100;
  58. var mousepoint = { x: 0, y: 0 };
  59. window.AudioContext = window.AudioContext || window.webkitAudioContext;
  60. if (!window.AudioContext) {
  61. console.log('当前浏览器不支持Web Audio API');
  62. }
  63. var audioCtx = new AudioContext();
  64. var arrFrequency = [196.00, 220.00, 246.94, 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25, 587.33, 659.25, 698.46, 783.99, 880.00, 987.77, 1046.50];
  65. function init(count) {
  66. if (planets.length > 300) return;
  67. var w = canvas.clientWidth;
  68. var h = canvas.clientHeight;
  69. for (var i = 0; i < count; i++) {
  70. planets.push({ x: Math.random() * w, y: Math.random() * h, mass: DEFAULT_MASS, vx: Math.random() * 2 - 1, vy: Math.random() * 2 - 1, lock: 0 });
  71. }
  72. }
  73. function fillRound(cx, cy, r, color) {
  74. context.beginPath();
  75. context.fillStyle = color;
  76. context.arc(cx, cy, Math.sqrt(r) / Math.PI, 0 * Math.PI, 2 * Math.PI, true);
  77. context.fill();
  78. }
  79. function drawLine(x1, y1, x2, y2, color) {
  80. context.beginPath();
  81. context.moveTo(x1, y1);
  82. context.strokeStyle = color;
  83. context.lineTo(x2, y2);
  84. context.stroke();
  85. }
  86. function collide() {
  87. for (var i = 0, count = planets.length; i < count; i++) {
  88. for (var i1 = 0; i1 < count; i1++) {
  89. if (i1 != i && planets[i1]) {
  90. if (planets[i].lock > 0 && planets[i1].lock > 0) continue;
  91. if ((planets[i].lock > 0 || planets[i1].lock > 0) && Math.random() > 0.1) continue;
  92. var r = Math.sqrt(Math.pow((planets[i].x - planets[i1].x), 2) + Math.pow((planets[i].y - planets[i1].y), 2));
  93. if (r <= Math.max(Math.sqrt(planets[i1].mass) / Math.PI + Math.sqrt(planets[i].mass) / Math.PI) && planets[i1].mass >= planets[i].mass) {
  94. var amplitude = Math.min(planets[i1].mass, planets[i].mass) / 1000 + (planets[i1].mass + planets[i].mass) / 2000;
  95. planets[i1].vy = (planets[i1].mass * planets[i1].vy + planets[i].mass * planets[i].vy) / (planets[i1].mass + planets[i].mass);
  96. planets[i1].vx = (planets[i1].mass * planets[i1].vx + planets[i].mass * planets[i].vx) / (planets[i1].mass + planets[i].mass);
  97. planets[i1].mass += planets[i].mass;
  98. planets[i] = null;
  99. var frequency = arrFrequency[Math.floor(Math.random() * 15)];
  100. var oscillator = audioCtx.createOscillator();
  101. var gainNode = audioCtx.createGain();
  102. oscillator.connect(gainNode);
  103. gainNode.connect(audioCtx.destination);
  104. oscillator.type = 'sawtooth';
  105. oscillator.frequency.value = frequency;
  106. gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
  107. gainNode.gain.linearRampToValueAtTime(amplitude, audioCtx.currentTime + 0.01);
  108. oscillator.start(audioCtx.currentTime);
  109. gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 1);
  110. oscillator.stop(audioCtx.currentTime + 1);
  111. break;
  112. }
  113. }
  114. }
  115. }
  116. }
  117. function explode() {
  118. for (var i = 0, count = planets.length; i < count; i++) {
  119. if (planets[i] && planets[i].mass >= MAX_MASS) {
  120. for (var i1 = 0; i1 < FRAGMENT_COUNT; i1++) {
  121. planets.push({
  122. x: planets[i].x + Math.random(),
  123. y: planets[i].y + Math.random(),
  124. mass: planets[i].mass / FRAGMENT_COUNT,
  125. vx: FRAGMENT_SPEED * (Math.random() * 2 - 1),
  126. vy: FRAGMENT_SPEED * (Math.random() * 2 - 1),
  127. lock: LOCK_TIME * (Math.random() + 1)
  128. });
  129. }
  130. var frequency = arrFrequency[Math.floor(Math.random() * 10)];
  131. var oscillator = audioCtx.createOscillator();
  132. var gainNode = audioCtx.createGain();
  133. oscillator.connect(gainNode);
  134. gainNode.connect(audioCtx.destination);
  135. oscillator.type = 'sine';
  136. oscillator.frequency.value = frequency;
  137. gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
  138. gainNode.gain.linearRampToValueAtTime(1.3, audioCtx.currentTime + 0.01);
  139. oscillator.start(audioCtx.currentTime);
  140. gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 10);
  141. oscillator.stop(audioCtx.currentTime + 10);
  142. planets[i] = null;
  143. }
  144. }
  145. }
  146. canvas.onmousemove = function (event) {
  147. var e = event || window.event;
  148. mousepoint = { 'x': e.clientX, 'y': e.clientY };
  149. }
  150. function step() {
  151. var w = canvas.clientWidth;
  152. var h = canvas.clientHeight;
  153. collide();
  154. explode();
  155. for (var i = 0, count = planets.length; i < count; i++) {
  156. if (planets[i]) {
  157. if (planets[i].vx === NaN) {
  158. planets[i].vx = 0
  159. }
  160. if (planets[i].vy === NaN) {
  161. planets[i].vy = 0
  162. }
  163. }
  164. }
  165. planets = planets.filter(e => e && e.x !== NaN && e.y !== NaN && e.vx !== NaN && e.vy !== NaN && e.mass !== NaN);
  166. for (var i = 0, count = planets.length; i < count; i++) {
  167. if (planets[i].x > w) {
  168. planets[i].x -= (planets[i].x - w) * 2;
  169. planets[i].vx *= -(1 - LOST);
  170. } else if (planets[i].x < 0) {
  171. planets[i].x += planets[i].x * -2;
  172. planets[i].vx *= -(1 - LOST);
  173. }
  174. if (planets[i].y > h) {
  175. planets[i].y -= (planets[i].y - h) * 2;
  176. planets[i].vy *= -(1 - LOST);
  177. } else if (planets[i].y < 0) {
  178. planets[i].y += planets[i].y * -2;
  179. planets[i].vy *= -(1 - LOST);
  180. }
  181. fillRound(planets[i].x, planets[i].y, planets[i].mass, COLOR)
  182. for (var i1 = 0; i1 < count; i1++) {
  183. if (i1 != i) {
  184. var r = Math.sqrt(Math.pow((planets[i].x - planets[i1].x), 2) + Math.pow((planets[i].y - planets[i1].y), 2));
  185. var f = r != 0 ? G * G * planets[i1].mass / Math.pow(r, 2) : 0;
  186. var dx = planets[i1].x - planets[i].x;
  187. var dy = planets[i1].y - planets[i].y;
  188. if (planets[i].mass > 0) {
  189. planets[i].vy += f / r * dy;
  190. planets[i].vx += f / r * dx;
  191. }
  192. if (i1 > i && r <= maxLineLength) {
  193. drawLine(planets[i].x, planets[i].y, planets[i1].x, planets[i1].y, LINE_COLOR)
  194. }
  195. }
  196. }
  197. //
  198. var r = Math.max(1, Math.sqrt(Math.pow((planets[i].x - mousepoint.x), 2) + Math.pow((planets[i].y - mousepoint.y), 2)));
  199. if (r > maxLineLength / 8) {
  200. var f = r != 0 ? G * G * MOUSE_MASS / Math.pow(r, 2) : 0;
  201. var dx = mousepoint.x - planets[i].x;
  202. var dy = mousepoint.y - planets[i].y;
  203. if (planets[i].mass > 0) {
  204. planets[i].vy += f / r * dy;
  205. planets[i].vx += f / r * dx;
  206. }
  207. if (r <= maxLineLength) {
  208. drawLine(planets[i].x, planets[i].y, mousepoint.x, mousepoint.y, LINE_COLOR);
  209. }
  210. }
  211. //
  212. var speedNow = Math.sqrt(Math.pow(planets[i].vx, 2) + Math.pow(planets[i].vy, 2))
  213. if (speedNow > MAX_SPEED) {
  214. planets[i].vx = planets[i].vx * MAX_SPEED / speedNow;
  215. planets[i].vy = planets[i].vy * MAX_SPEED / speedNow;
  216. }
  217. planets[i].x += planets[i].vx;
  218. planets[i].y += planets[i].vy;
  219. planets[i].lock--;
  220. }
  221. }
  222. // init(PLANET_COUNT);
  223. setInterval(function () {
  224. var w = document.body.clientWidth;
  225. var h = document.body.clientHeight;
  226. maxLineLength = Math.max(30, Math.min(w / 10, h / 10));
  227. canvas.setAttribute('width', w);
  228. canvas.setAttribute('height', h);
  229. canvas.style.width = w + 'px';
  230. canvas.style.height = h + 'px';
  231. step();
  232. }, 30)
  233. </script>
  234. </html>