engerl commited on
Commit
25cd845
·
verified ·
1 Parent(s): 7490721

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +636 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Space
3
- emoji: 🏃
4
- colorFrom: purple
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: space
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,636 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>宇宙行星球體空間扭曲現象</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ body {
10
+ margin: 0;
11
+ overflow: hidden;
12
+ background-color: #000;
13
+ cursor: grab;
14
+ }
15
+ body.grabbing {
16
+ cursor: grabbing;
17
+ }
18
+ canvas {
19
+ display: block;
20
+ }
21
+ .info-panel {
22
+ position: absolute;
23
+ bottom: 20px;
24
+ left: 20px;
25
+ background: rgba(0, 0, 0, 0.7);
26
+ color: white;
27
+ padding: 15px;
28
+ border-radius: 10px;
29
+ max-width: 300px;
30
+ font-family: 'Arial', sans-serif;
31
+ }
32
+ .title {
33
+ position: absolute;
34
+ top: 20px;
35
+ left: 50%;
36
+ transform: translateX(-50%);
37
+ color: white;
38
+ font-size: 2rem;
39
+ text-align: center;
40
+ text-shadow: 0 0 10px #4f8fff;
41
+ font-family: 'Arial', sans-serif;
42
+ }
43
+ .controls {
44
+ position: absolute;
45
+ top: 20px;
46
+ right: 20px;
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: 10px;
50
+ }
51
+ .control-btn {
52
+ background: rgba(0, 0, 0, 0.7);
53
+ color: white;
54
+ border: 1px solid #4f8fff;
55
+ border-radius: 5px;
56
+ padding: 8px 12px;
57
+ cursor: pointer;
58
+ transition: all 0.3s;
59
+ }
60
+ .control-btn:hover {
61
+ background: rgba(79, 143, 255, 0.3);
62
+ }
63
+ .star {
64
+ position: absolute;
65
+ background-color: white;
66
+ border-radius: 50%;
67
+ pointer-events: none;
68
+ }
69
+ </style>
70
+ </head>
71
+ <body>
72
+ <div class="title">宇宙行星球體空間扭曲現象</div>
73
+
74
+ <div class="controls">
75
+ <button id="addPlanet" class="control-btn">添加行星</button>
76
+ <button id="reset" class="control-btn">重置模擬</button>
77
+ <button id="toggleGravity" class="control-btn">切換引力</button>
78
+ <button id="toggleDistortion" class="control-btn">切換扭曲效果</button>
79
+ <button id="resetView" class="control-btn">重置視角</button>
80
+ </div>
81
+
82
+ <div class="info-panel">
83
+ <h3 class="text-xl font-bold mb-2 text-blue-300">空間扭曲現象</h3>
84
+ <p class="text-sm mb-2">當大質量天體在時空中移動時,會造成周圍空間的彎曲和扭曲,這正是愛因斯坦廣義相對論所描述的現象。</p>
85
+ <p class="text-sm">在此模擬中,行星的運動會在其周圍產生引力井效應,導致光線偏折和空間變形。</p>
86
+ <p class="text-sm mt-2 text-blue-200">提示: 用滑鼠拖曳可以改變視角</p>
87
+ </div>
88
+
89
+ <canvas id="spaceCanvas"></canvas>
90
+
91
+ <script>
92
+ // 初始化畫布
93
+ const canvas = document.getElementById('spaceCanvas');
94
+ const ctx = canvas.getContext('2d');
95
+
96
+ // 設置畫布大小為窗口大小
97
+ function resizeCanvas() {
98
+ canvas.width = window.innerWidth;
99
+ canvas.height = window.innerHeight;
100
+ }
101
+ resizeCanvas();
102
+ window.addEventListener('resize', resizeCanvas);
103
+
104
+ // 模擬參數
105
+ const params = {
106
+ gravity: true,
107
+ distortion: true,
108
+ distortionStrength: 0.3,
109
+ friction: 0.98,
110
+ bounce: 0.7,
111
+ starCount: 200
112
+ };
113
+
114
+ // 視角控制
115
+ const view = {
116
+ x: 0,
117
+ y: 0,
118
+ scale: 1,
119
+ isDragging: false,
120
+ lastX: 0,
121
+ lastY: 0
122
+ };
123
+
124
+ // 行星類
125
+ class Planet {
126
+ constructor(x, y, radius, mass, color) {
127
+ this.x = x;
128
+ this.y = y;
129
+ this.radius = radius;
130
+ this.mass = mass;
131
+ this.color = color;
132
+ this.vx = (Math.random() - 0.5) * 5;
133
+ this.vy = (Math.random() - 0.5) * 5;
134
+ this.rotation = 0;
135
+ this.rotationSpeed = (Math.random() - 0.5) * 0.02;
136
+ this.texture = this.createTexture(radius, color);
137
+ }
138
+
139
+ createTexture(radius, color) {
140
+ const textureCanvas = document.createElement('canvas');
141
+ const textureCtx = textureCanvas.getContext('2d');
142
+ const size = radius * 2;
143
+ textureCanvas.width = size;
144
+ textureCanvas.height = size;
145
+
146
+ // 繪製行星紋理
147
+ const gradient = textureCtx.createRadialGradient(
148
+ radius, radius, 0,
149
+ radius, radius, radius
150
+ );
151
+ gradient.addColorStop(0, lightenColor(color, 30));
152
+ gradient.addColorStop(0.7, color);
153
+ gradient.addColorStop(1, darkenColor(color, 20));
154
+
155
+ textureCtx.beginPath();
156
+ textureCtx.arc(radius, radius, radius, 0, Math.PI * 2);
157
+ textureCtx.fillStyle = gradient;
158
+ textureCtx.fill();
159
+
160
+ // 添加一些隨機的斑點紋理
161
+ for (let i = 0; i < radius / 2; i++) {
162
+ const spotRadius = Math.random() * radius / 4;
163
+ const spotX = Math.random() * size;
164
+ const spotY = Math.random() * size;
165
+
166
+ // 確保斑點在行星內部
167
+ const dist = Math.sqrt(
168
+ Math.pow(spotX - radius, 2) +
169
+ Math.pow(spotY - radius, 2)
170
+ );
171
+
172
+ if (dist < radius - spotRadius) {
173
+ const spotColor = Math.random() > 0.5 ?
174
+ lightenColor(color, 15) :
175
+ darkenColor(color, 15);
176
+
177
+ textureCtx.beginPath();
178
+ textureCtx.arc(spotX, spotY, spotRadius, 0, Math.PI * 2);
179
+ textureCtx.fillStyle = spotColor;
180
+ textureCtx.fill();
181
+ }
182
+ }
183
+
184
+ return textureCanvas;
185
+ }
186
+
187
+ update() {
188
+ this.x += this.vx;
189
+ this.y += this.vy;
190
+ this.rotation += this.rotationSpeed;
191
+
192
+ // 邊界碰撞檢測 - 現在基於原始空間而非視口
193
+ const scaledWidth = canvas.width / view.scale;
194
+ const scaledHeight = canvas.height / view.scale;
195
+
196
+ if (this.x - this.radius < 0) {
197
+ this.x = this.radius;
198
+ this.vx = -this.vx * params.bounce;
199
+ } else if (this.x + this.radius > scaledWidth) {
200
+ this.x = scaledWidth - this.radius;
201
+ this.vx = -this.vx * params.bounce;
202
+ }
203
+
204
+ if (this.y - this.radius < 0) {
205
+ this.y = this.radius;
206
+ this.vy = -this.vy * params.bounce;
207
+ } else if (this.y + this.radius > scaledHeight) {
208
+ this.y = scaledHeight - this.radius;
209
+ this.vy = -this.vy * params.bounce;
210
+ }
211
+
212
+ // 應用摩擦力
213
+ this.vx *= params.friction;
214
+ this.vy *= params.friction;
215
+ }
216
+
217
+ draw() {
218
+ ctx.save();
219
+
220
+ // 應用視角變換
221
+ ctx.translate(view.x, view.y);
222
+ ctx.scale(view.scale, view.scale);
223
+
224
+ ctx.translate(this.x, this.y);
225
+ ctx.rotate(this.rotation);
226
+
227
+ // 繪製行星
228
+ ctx.drawImage(
229
+ this.texture,
230
+ -this.radius,
231
+ -this.radius,
232
+ this.radius * 2,
233
+ this.radius * 2
234
+ );
235
+
236
+ // 繪製行星光暈
237
+ if (params.distortion) {
238
+ const gradient = ctx.createRadialGradient(
239
+ 0, 0, this.radius,
240
+ 0, 0, this.radius * 2
241
+ );
242
+ gradient.addColorStop(0, `rgba(${hexToRgb(this.color)}, 0.3)`);
243
+ gradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
244
+
245
+ ctx.beginPath();
246
+ ctx.arc(0, 0, this.radius * 2, 0, Math.PI * 2);
247
+ ctx.fillStyle = gradient;
248
+ ctx.fill();
249
+ }
250
+
251
+ ctx.restore();
252
+ }
253
+
254
+ applyGravity(otherPlanets) {
255
+ if (!params.gravity) return;
256
+
257
+ otherPlanets.forEach(planet => {
258
+ if (planet !== this) {
259
+ const dx = planet.x - this.x;
260
+ const dy = planet.y - this.y;
261
+ const distance = Math.sqrt(dx * dx + dy * dy);
262
+
263
+ // 避免除以零和極端力
264
+ if (distance > 5) {
265
+ const force = (planet.mass * this.mass) / (distance * distance) * 0.0001;
266
+ const fx = (dx / distance) * force;
267
+ const fy = (dy / distance) * force;
268
+
269
+ this.vx += fx / this.mass;
270
+ this.vy += fy / this.mass;
271
+ }
272
+ }
273
+ });
274
+ }
275
+
276
+ // 獲取行星在屏幕上的位置
277
+ getScreenPosition() {
278
+ return {
279
+ x: this.x * view.scale + view.x,
280
+ y: this.y * view.scale + view.y
281
+ };
282
+ }
283
+ }
284
+
285
+ // 恆星類
286
+ class Star {
287
+ constructor() {
288
+ this.x = Math.random() * (canvas.width / view.scale);
289
+ this.y = Math.random() * (canvas.height / view.scale);
290
+ this.size = Math.random() * 3;
291
+ this.brightness = Math.random();
292
+ this.color = `rgba(255, 255, 255, ${this.brightness})`;
293
+ this.speed = 0.1 + Math.random() * 0.5;
294
+ this.direction = Math.random() * Math.PI * 2;
295
+ }
296
+
297
+ update(planets) {
298
+ // 恆星受行星引力影響
299
+ if (params.gravity) {
300
+ planets.forEach(planet => {
301
+ const dx = planet.x - this.x;
302
+ const dy = planet.y - this.y;
303
+ const distance = Math.sqrt(dx * dx + dy * dy);
304
+
305
+ if (distance < planet.radius * 3) {
306
+ const angle = Math.atan2(dy, dx);
307
+ const force = (planet.mass * 0.0001) / (distance * distance);
308
+
309
+ this.x -= Math.cos(angle) * force * 10;
310
+ this.y -= Math.sin(angle) * force * 10;
311
+ }
312
+ });
313
+ }
314
+
315
+ // 恆星基本運動
316
+ this.x += Math.cos(this.direction) * this.speed;
317
+ this.y += Math.sin(this.direction) * this.speed;
318
+
319
+ // 邊界檢查 - 現在基於原始空間而非視口
320
+ const scaledWidth = canvas.width / view.scale;
321
+ const scaledHeight = canvas.height / view.scale;
322
+
323
+ if (this.x < 0 || this.x > scaledWidth ||
324
+ this.y < 0 || this.y > scaledHeight) {
325
+ this.x = Math.random() * scaledWidth;
326
+ this.y = Math.random() * scaledHeight;
327
+ this.direction = Math.random() * Math.PI * 2;
328
+ }
329
+ }
330
+
331
+ draw() {
332
+ ctx.save();
333
+ ctx.translate(view.x, view.y);
334
+ ctx.scale(view.scale, view.scale);
335
+
336
+ ctx.fillStyle = this.color;
337
+ ctx.beginPath();
338
+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
339
+ ctx.fill();
340
+
341
+ ctx.restore();
342
+ }
343
+ }
344
+
345
+ // 工具函數
346
+ function lightenColor(color, percent) {
347
+ const num = parseInt(color.replace("#", ""), 16);
348
+ const amt = Math.round(2.55 * percent);
349
+ const R = (num >> 16) + amt;
350
+ const G = (num >> 8 & 0x00FF) + amt;
351
+ const B = (num & 0x0000FF) + amt;
352
+
353
+ return `#${(
354
+ 0x1000000 +
355
+ (R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 +
356
+ (G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 +
357
+ (B < 255 ? (B < 1 ? 0 : B) : 255)
358
+ ).toString(16).slice(1)}`;
359
+ }
360
+
361
+ function darkenColor(color, percent) {
362
+ const num = parseInt(color.replace("#", ""), 16);
363
+ const amt = Math.round(2.55 * percent);
364
+ const R = (num >> 16) - amt;
365
+ const G = (num >> 8 & 0x00FF) - amt;
366
+ const B = (num & 0x0000FF) - amt;
367
+
368
+ return `#${(
369
+ 0x1000000 +
370
+ (R > 0 ? (R < 255 ? R : 255) : 0) * 0x10000 +
371
+ (G > 0 ? (G < 255 ? G : 255) : 0) * 0x100 +
372
+ (B > 0 ? (B < 255 ? B : 255) : 0)
373
+ ).toString(16).slice(1)}`;
374
+ }
375
+
376
+ function hexToRgb(hex) {
377
+ const r = parseInt(hex.slice(1, 3), 16);
378
+ const g = parseInt(hex.slice(3, 5), 16);
379
+ const b = parseInt(hex.slice(5, 7), 16);
380
+ return `${r}, ${g}, ${b}`;
381
+ }
382
+
383
+ function getRandomPlanetColor() {
384
+ const colors = [
385
+ '#4A6FA5', // 藍色
386
+ '#A54A4A', // 紅色
387
+ '#4AA54A', // 綠色
388
+ '#A54AA5', // 紫色
389
+ '#A5A54A', // 黃色
390
+ '#4AA5A5', // 青色
391
+ '#A56F4A' // 橙色
392
+ ];
393
+ return colors[Math.floor(Math.random() * colors.length)];
394
+ }
395
+
396
+ // 初始化行星和恆星
397
+ let planets = [];
398
+ let stars = [];
399
+
400
+ function init() {
401
+ planets = [];
402
+ stars = [];
403
+
404
+ // 創建一些初始行星
405
+ for (let i = 0; i < 3; i++) {
406
+ const radius = 20 + Math.random() * 30;
407
+ planets.push(new Planet(
408
+ Math.random() * (canvas.width / view.scale - radius * 2) + radius,
409
+ Math.random() * (canvas.height / view.scale - radius * 2) + radius,
410
+ radius,
411
+ radius * radius * 0.1,
412
+ getRandomPlanetColor()
413
+ ));
414
+ }
415
+
416
+ // 創建恆星背景
417
+ for (let i = 0; i < params.starCount; i++) {
418
+ stars.push(new Star());
419
+ }
420
+
421
+ // 重置視角
422
+ resetView();
423
+ }
424
+
425
+ // 重置視角
426
+ function resetView() {
427
+ view.x = 0;
428
+ view.y = 0;
429
+ view.scale = 1;
430
+ }
431
+
432
+ // 動畫循環
433
+ function animate() {
434
+ // 清除畫布
435
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
436
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
437
+
438
+ // 繪製扭曲網格
439
+ if (params.distortion) {
440
+ drawSpaceGrid();
441
+ }
442
+
443
+ // 更新和繪製恆星
444
+ stars.forEach(star => {
445
+ star.update(planets);
446
+ star.draw();
447
+ });
448
+
449
+ // 更新和繪製行星
450
+ planets.forEach(planet => {
451
+ planet.applyGravity(planets);
452
+ planet.update();
453
+ planet.draw();
454
+ });
455
+
456
+ requestAnimationFrame(animate);
457
+ }
458
+
459
+ // 繪製空間網格以展示扭曲效果
460
+ function drawSpaceGrid() {
461
+ const gridSize = 40;
462
+ const rows = Math.ceil(canvas.height / (gridSize * view.scale));
463
+ const cols = Math.ceil(canvas.width / (gridSize * view.scale));
464
+
465
+ ctx.save();
466
+ ctx.translate(view.x, view.y);
467
+ ctx.scale(view.scale, view.scale);
468
+
469
+ ctx.strokeStyle = 'rgba(100, 150, 255, 0.2)';
470
+ ctx.lineWidth = 1 / view.scale;
471
+
472
+ // 繪製水平線
473
+ for (let i = 0; i < rows; i++) {
474
+ const y = i * gridSize;
475
+ ctx.beginPath();
476
+
477
+ for (let j = 0; j < cols; j++) {
478
+ const x = j * gridSize;
479
+ let newX = x;
480
+ let newY = y;
481
+
482
+ // 應用行星引力扭曲
483
+ planets.forEach(planet => {
484
+ const dx = x - planet.x;
485
+ const dy = y - planet.y;
486
+ const distance = Math.sqrt(dx * dx + dy * dy);
487
+
488
+ if (distance < planet.radius * 5) {
489
+ const strength = params.distortionStrength * (planet.mass / 100) * (1 - distance / (planet.radius * 5));
490
+ const angle = Math.atan2(dy, dx);
491
+
492
+ newX -= Math.cos(angle) * strength * 10;
493
+ newY -= Math.sin(angle) * strength * 10;
494
+ }
495
+ });
496
+
497
+ if (j === 0) {
498
+ ctx.moveTo(newX, newY);
499
+ } else {
500
+ ctx.lineTo(newX, newY);
501
+ }
502
+ }
503
+
504
+ ctx.stroke();
505
+ }
506
+
507
+ // 繪製垂直線
508
+ for (let j = 0; j < cols; j++) {
509
+ const x = j * gridSize;
510
+ ctx.beginPath();
511
+
512
+ for (let i = 0; i < rows; i++) {
513
+ const y = i * gridSize;
514
+ let newX = x;
515
+ let newY = y;
516
+
517
+ // 應用行星引力扭曲
518
+ planets.forEach(planet => {
519
+ const dx = x - planet.x;
520
+ const dy = y - planet.y;
521
+ const distance = Math.sqrt(dx * dx + dy * dy);
522
+
523
+ if (distance < planet.radius * 5) {
524
+ const strength = params.distortionStrength * (planet.mass / 100) * (1 - distance / (planet.radius * 5));
525
+ const angle = Math.atan2(dy, dx);
526
+
527
+ newX -= Math.cos(angle) * strength * 10;
528
+ newY -= Math.sin(angle) * strength * 10;
529
+ }
530
+ });
531
+
532
+ if (i === 0) {
533
+ ctx.moveTo(newX, newY);
534
+ } else {
535
+ ctx.lineTo(newX, newY);
536
+ }
537
+ }
538
+
539
+ ctx.stroke();
540
+ }
541
+
542
+ ctx.restore();
543
+ }
544
+
545
+ // 事件監聽器
546
+ document.getElementById('addPlanet').addEventListener('click', () => {
547
+ const radius = 20 + Math.random() * 30;
548
+ planets.push(new Planet(
549
+ Math.random() * (canvas.width / view.scale - radius * 2) + radius,
550
+ Math.random() * (canvas.height / view.scale - radius * 2) + radius,
551
+ radius,
552
+ radius * radius * 0.1,
553
+ getRandomPlanetColor()
554
+ ));
555
+ });
556
+
557
+ document.getElementById('reset').addEventListener('click', init);
558
+
559
+ document.getElementById('toggleGravity').addEventListener('click', () => {
560
+ params.gravity = !params.gravity;
561
+ document.getElementById('toggleGravity').textContent =
562
+ params.gravity ? '關閉引力' : '開啟引力';
563
+ });
564
+
565
+ document.getElementById('toggleDistortion').addEventListener('click', () => {
566
+ params.distortion = !params.distortion;
567
+ document.getElementById('toggleDistortion').textContent =
568
+ params.distortion ? '關閉扭曲' : '開啟扭曲';
569
+ });
570
+
571
+ document.getElementById('resetView').addEventListener('click', resetView);
572
+
573
+ // 滑鼠拖曳事件
574
+ canvas.addEventListener('mousedown', (e) => {
575
+ view.isDragging = true;
576
+ view.lastX = e.clientX;
577
+ view.lastY = e.clientY;
578
+ document.body.classList.add('grabbing');
579
+ });
580
+
581
+ canvas.addEventListener('mousemove', (e) => {
582
+ if (view.isDragging) {
583
+ const dx = e.clientX - view.lastX;
584
+ const dy = e.clientY - view.lastY;
585
+
586
+ view.x += dx;
587
+ view.y += dy;
588
+
589
+ view.lastX = e.clientX;
590
+ view.lastY = e.clientY;
591
+ }
592
+ });
593
+
594
+ canvas.addEventListener('mouseup', () => {
595
+ view.isDragging = false;
596
+ document.body.classList.remove('grabbing');
597
+ });
598
+
599
+ canvas.addEventListener('mouseleave', () => {
600
+ view.isDragging = false;
601
+ document.body.classList.remove('grabbing');
602
+ });
603
+
604
+ // 滑鼠滾輪縮放
605
+ canvas.addEventListener('wheel', (e) => {
606
+ e.preventDefault();
607
+
608
+ // 獲取滑鼠位置相對於畫布的座標
609
+ const mouseX = e.clientX - canvas.getBoundingClientRect().left;
610
+ const mouseY = e.clientY - canvas.getBoundingClientRect().top;
611
+
612
+ // 計算滑鼠在原始空間中的位置
613
+ const worldX = (mouseX - view.x) / view.scale;
614
+ const worldY = (mouseY - view.y) / view.scale;
615
+
616
+ // 計算縮放因子
617
+ const delta = -e.deltaY;
618
+ const zoomFactor = delta > 0 ? 1.1 : 0.9;
619
+
620
+ // 限制縮放範圍
621
+ const newScale = view.scale * zoomFactor;
622
+ if (newScale > 0.1 && newScale < 5) {
623
+ view.scale = newScale;
624
+
625
+ // 調整視圖位置以保持滑鼠下的點不變
626
+ view.x = mouseX - worldX * view.scale;
627
+ view.y = mouseY - worldY * view.scale;
628
+ }
629
+ });
630
+
631
+ // 初始化並開始動畫
632
+ init();
633
+ animate();
634
+ </script>
635
+ <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=engerl/space" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
636
+ </html>