Ramesh-vani commited on
Commit
cc20f6c
·
verified ·
1 Parent(s): cc43bb5

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +694 -18
index.html CHANGED
@@ -1,19 +1,695 @@
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="hi">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Responsive Physics Simulator with Menus on Top</title>
6
+ <style>
7
+ body { margin: 0; overflow: hidden; font-family: Arial, sans-serif; }
8
+ /* Full-page canvas */
9
+ canvas { display: block; }
10
+ /* Controls Panel (Menus) – z-index high to always appear on top */
11
+ #controls {
12
+ position: absolute;
13
+ top: 10px;
14
+ left: 10px;
15
+ z-index: 1000;
16
+ background: rgba(255,255,255,0.95);
17
+ padding: 10px;
18
+ border-radius: 5px;
19
+ max-width: 320px;
20
+ max-height: 90vh;
21
+ overflow-y: auto;
22
+ }
23
+ #controls label { display: block; margin-top: 8px; }
24
+ #controls input, #controls select, #controls button {
25
+ width: 100%; padding: 6px; margin-top: 4px; box-sizing: border-box;
26
+ }
27
+ #buttonContainer { display: flex; justify-content: space-between; }
28
+ /* Edit Panel – Always on top */
29
+ #editPanel {
30
+ position: absolute;
31
+ top: 10px;
32
+ right: 10px;
33
+ z-index: 1000;
34
+ background: rgba(255,255,255,0.95);
35
+ padding: 10px;
36
+ border-radius: 5px;
37
+ max-width: 300px;
38
+ max-height: 90vh;
39
+ overflow-y: auto;
40
+ display: none;
41
+ }
42
+ #editPanel h3 { margin: 0 0 5px 0; }
43
+ #editPanel label { display: block; margin-top: 8px; }
44
+ #editPanel input, #editPanel select, #editPanel button {
45
+ width: 100%; padding: 6px; margin-top: 4px; box-sizing: border-box;
46
+ }
47
+ /* Connection Options Panel */
48
+ #connectionPanel {
49
+ position: absolute;
50
+ top: 150px;
51
+ right: 10px;
52
+ z-index: 1000;
53
+ background: rgba(255,255,255,0.95);
54
+ padding: 10px;
55
+ border-radius: 5px;
56
+ max-width: 250px;
57
+ display: none;
58
+ }
59
+ #connectionPanel h3 { margin: 0 0 5px 0; }
60
+ #connectionPanel label { display: block; margin-top: 8px; }
61
+ #connectionPanel input, #connectionPanel select, #connectionPanel button {
62
+ width: 100%; padding: 6px; margin-top: 4px; box-sizing: border-box;
63
+ }
64
+ /* Constraint Edit Panel */
65
+ #constraintEditPanel {
66
+ position: absolute;
67
+ bottom: 10px;
68
+ right: 10px;
69
+ z-index: 1000;
70
+ background: rgba(255,255,255,0.95);
71
+ padding: 10px;
72
+ border-radius: 5px;
73
+ max-width: 250px;
74
+ display: none;
75
+ }
76
+ #constraintEditPanel h3 { margin: 0 0 5px 0; }
77
+ #constraintEditPanel label { display: block; margin-top: 8px; }
78
+ #constraintEditPanel input, #constraintEditPanel select, #constraintEditPanel button {
79
+ width: 100%; padding: 6px; margin-top: 4px; box-sizing: border-box;
80
+ }
81
+ </style>
82
+ </head>
83
+ <body>
84
+ <!-- Controls Panel (Menus) -->
85
+ <div id="controls">
86
+ <label for="simulationSelect">Simulation Element Chunein:</label>
87
+ <select id="simulationSelect">
88
+ <option value="bouncingBall">Bouncing Ball</option>
89
+ <option value="pendulum">Pendulum</option>
90
+ <option value="projectile">Projectile Motion</option>
91
+ <option value="inclinedPlane">Inclined Plane</option>
92
+ <option value="springMass">Spring–Mass System</option>
93
+ </select>
94
+ <!-- Dynamic Suboptions Container -->
95
+ <div id="subOptionsContainer"></div>
96
+ <div id="buttonContainer">
97
+ <button id="addElement">Add Element</button>
98
+ <button id="reset">Reset Simulation</button>
99
+ </div>
100
+ </div>
101
+
102
+ <!-- Edit Panel (Opens on Double–Click on an Element) -->
103
+ <div id="editPanel"></div>
104
+
105
+ <!-- Connection Options Panel -->
106
+ <div id="connectionPanel">
107
+ <h3>Connection Options</h3>
108
+ <label for="connType">Connection Type:</label>
109
+ <select id="connType">
110
+ <option value="string">String</option>
111
+ <option value="spring">Spring</option>
112
+ <option value="stick">Stick</option>
113
+ </select>
114
+ <div id="sourceEndpointDiv">
115
+ <label for="sourceEndpoint">Source Endpoint:</label>
116
+ <select id="sourceEndpoint">
117
+ <option value="mass">Mass</option>
118
+ <option value="fixed">Fixed</option>
119
+ </select>
120
+ </div>
121
+ <button id="cancelConn">Cancel</button>
122
+ <p style="font-size: 12px; color: #555;">Ab target element par click karein jisse attach karna hai.</p>
123
+ </div>
124
+
125
+ <!-- Constraint Edit Panel -->
126
+ <div id="constraintEditPanel">
127
+ <h3>Edit Constraint</h3>
128
+ <label for="consA_X">Endpoint A X:</label>
129
+ <input type="number" id="consA_X" step="1">
130
+ <label for="consA_Y">Endpoint A Y:</label>
131
+ <input type="number" id="consA_Y" step="1">
132
+ <label for="consB_X">Endpoint B X:</label>
133
+ <input type="number" id="consB_X" step="1">
134
+ <label for="consB_Y">Endpoint B Y:</label>
135
+ <input type="number" id="consB_Y" step="1">
136
+ <label for="consType">Connection Type:</label>
137
+ <select id="consType">
138
+ <option value="string">String</option>
139
+ <option value="spring">Spring</option>
140
+ <option value="stick">Stick</option>
141
+ </select>
142
+ <button id="updateConstraint">Update Constraint</button>
143
+ <button id="deleteConstraint">Delete Constraint</button>
144
+ </div>
145
+
146
+ <!-- Matter.js Library and Script -->
147
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
148
+ <script>
149
+ // Module aliases and Engine Setup
150
+ const Engine = Matter.Engine,
151
+ Render = Matter.Render,
152
+ Runner = Matter.Runner,
153
+ World = Matter.World,
154
+ Bodies = Matter.Bodies,
155
+ Body = Matter.Body,
156
+ Constraint = Matter.Constraint,
157
+ Mouse = Matter.Mouse,
158
+ MouseConstraint = Matter.MouseConstraint,
159
+ Events = Matter.Events;
160
+
161
+ const engine = Engine.create();
162
+ const world = engine.world;
163
+ const render = Render.create({
164
+ element: document.body,
165
+ engine: engine,
166
+ options: {
167
+ width: window.innerWidth,
168
+ height: window.innerHeight,
169
+ wireframes: false,
170
+ background: '#f0f0f0'
171
+ }
172
+ });
173
+ Render.run(render);
174
+ const runner = Runner.create();
175
+ Runner.run(runner, engine);
176
+
177
+ // Global variables for boundaries (declare as let so we can update them)
178
+ let floor, wallLeft, wallRight;
179
+
180
+ // Function to create/update boundaries based on current window dimensions
181
+ function updateBoundaries() {
182
+ // Agar boundaries already exist, remove unhein
183
+ if(floor && wallLeft && wallRight) {
184
+ World.remove(world, [floor, wallLeft, wallRight]);
185
+ }
186
+ floor = Bodies.rectangle(window.innerWidth/2, window.innerHeight - 50, window.innerWidth, 100, {
187
+ isStatic: true,
188
+ render: { fillStyle: '#060a19' }
189
+ });
190
+ wallLeft = Bodies.rectangle(-50, window.innerHeight/2, 100, window.innerHeight, { isStatic: true });
191
+ wallRight = Bodies.rectangle(window.innerWidth+50, window.innerHeight/2, 100, window.innerHeight, { isStatic: true });
192
+ World.add(world, [floor, wallLeft, wallRight]);
193
+ }
194
+ // Initial boundaries creation
195
+ updateBoundaries();
196
+
197
+ // Mouse control for drag & drop
198
+ let mouse = Mouse.create(render.canvas);
199
+ let mouseConstraint = MouseConstraint.create(engine, {
200
+ mouse: mouse,
201
+ constraint: { stiffness: 0.2, render: { visible: false } }
202
+ });
203
+ World.add(world, mouseConstraint);
204
+ render.mouse = mouse;
205
+
206
+ // Global Variables for Editing & Attachment
207
+ let selectedBody = null;
208
+ let selectedConstraint = null;
209
+ let attachMode = false;
210
+ let attachFrom = null;
211
+ const connectionPanel = document.getElementById('connectionPanel');
212
+ const editPanel = document.getElementById('editPanel');
213
+
214
+ // Helper function for random color
215
+ function getRandomColor() {
216
+ return '#' + Math.floor(Math.random()*16777215).toString(16);
217
+ }
218
+
219
+ /* ---------- Dynamic Suboptions for Adding Elements ---------- */
220
+ function updateSubOptions() {
221
+ const simulationSelect = document.getElementById('simulationSelect');
222
+ const subOptionsContainer = document.getElementById('subOptionsContainer');
223
+ let selected = simulationSelect.value;
224
+ let html = '';
225
+ if(selected === 'bouncingBall'){
226
+ html += `
227
+ <label for="ballInitialX">Initial X:</label>
228
+ <input type="number" id="ballInitialX" value="100">
229
+ <label for="ballInitialY">Initial Y:</label>
230
+ <input type="number" id="ballInitialY" value="50">
231
+ <label for="ballRadius">Radius:</label>
232
+ <input type="number" id="ballRadius" value="30">
233
+ <label for="ballRestitution">Restitution:</label>
234
+ <input type="number" id="ballRestitution" value="0.9" step="0.1" min="0" max="1">
235
+ <label for="ballFriction">Friction:</label>
236
+ <input type="number" id="ballFriction" value="0.005" step="0.001" min="0" max="1">
237
+ <label for="ballColor">Color:</label>
238
+ <input type="color" id="ballColor" value="#3498db">
239
+ `;
240
+ } else if(selected === 'pendulum'){
241
+ html += `
242
+ <label for="pendulumPivotX">Pivot X:</label>
243
+ <input type="number" id="pendulumPivotX" value="${window.innerWidth-200}">
244
+ <label for="pendulumPivotY">Pivot Y:</label>
245
+ <input type="number" id="pendulumPivotY" value="50">
246
+ <label for="pendulumBobRadius">Bob Radius:</label>
247
+ <input type="number" id="pendulumBobRadius" value="40">
248
+ <label for="pendulumLength">Length:</label>
249
+ <input type="number" id="pendulumLength" value="250">
250
+ <label for="pendulumStiffness">Stiffness:</label>
251
+ <input type="number" id="pendulumStiffness" value="1" step="0.1" min="0" max="1">
252
+ <label for="pendulumBobColor">Color:</label>
253
+ <input type="color" id="pendulumBobColor" value="#ff0000">
254
+ `;
255
+ } else if(selected === 'projectile'){
256
+ html += `
257
+ <label for="projectileInitialX">Initial X:</label>
258
+ <input type="number" id="projectileInitialX" value="100">
259
+ <label for="projectileInitialY">Initial Y:</label>
260
+ <input type="number" id="projectileInitialY" value="300">
261
+ <label for="projectileRadius">Radius:</label>
262
+ <input type="number" id="projectileRadius" value="20">
263
+ <label for="projectileVelX">Velocity X:</label>
264
+ <input type="number" id="projectileVelX" value="15">
265
+ <label for="projectileVelY">Velocity Y:</label>
266
+ <input type="number" id="projectileVelY" value="-15">
267
+ <label for="projectileColor">Color:</label>
268
+ <input type="color" id="projectileColor" value="#e67e22">
269
+ `;
270
+ } else if(selected === 'inclinedPlane'){
271
+ html += `
272
+ <label for="rampWidth">Ramp Width:</label>
273
+ <input type="number" id="rampWidth" value="300">
274
+ <label for="rampHeight">Ramp Height:</label>
275
+ <input type="number" id="rampHeight" value="20">
276
+ <label for="rampAngle">Ramp Angle (°):</label>
277
+ <input type="number" id="rampAngle" value="30">
278
+ <label for="rampX">Ramp X:</label>
279
+ <input type="number" id="rampX" value="400">
280
+ <label for="rampY">Ramp Y:</label>
281
+ <input type="number" id="rampY" value="${window.innerHeight-150}">
282
+ <label for="rampColor">Ramp Color:</label>
283
+ <input type="color" id="rampColor" value="#8e44ad">
284
+ <hr>
285
+ <label for="blockWidth">Block Width:</label>
286
+ <input type="number" id="blockWidth" value="40">
287
+ <label for="blockHeight">Block Height:</label>
288
+ <input type="number" id="blockHeight" value="40">
289
+ <label for="blockFriction">Block Friction:</label>
290
+ <input type="number" id="blockFriction" value="0.05" step="0.01" min="0" max="1">
291
+ <label for="blockColor">Block Color:</label>
292
+ <input type="color" id="blockColor" value="#1abc9c">
293
+ `;
294
+ } else if(selected === 'springMass'){
295
+ html += `
296
+ <label for="springMassRadius">Mass Radius:</label>
297
+ <input type="number" id="springMassRadius" value="25">
298
+ <label for="springMassRestitution">Restitution:</label>
299
+ <input type="number" id="springMassRestitution" value="0.8" step="0.1" min="0" max="1">
300
+ <label for="fixedPointX">Fixed X:</label>
301
+ <input type="number" id="fixedPointX" value="${Math.floor(window.innerWidth/2)}">
302
+ <label for="fixedPointY">Fixed Y:</label>
303
+ <input type="number" id="fixedPointY" value="100">
304
+ <label for="springLength">Spring Length:</label>
305
+ <input type="number" id="springLength" value="200">
306
+ <label for="springStiffness">Stiffness:</label>
307
+ <input type="number" id="springStiffness" value="0.02" step="0.01" min="0" max="1">
308
+ <label for="springMassColor">Color:</label>
309
+ <input type="color" id="springMassColor" value="#f39c12">
310
+ `;
311
+ }
312
+ subOptionsContainer.innerHTML = html;
313
+ }
314
+ updateSubOptions();
315
+ document.getElementById('simulationSelect').addEventListener('change', updateSubOptions);
316
+
317
+ /* ---------- Functions to Add Simulation Elements ---------- */
318
+ function addBouncingBall(){
319
+ const x = parseFloat(document.getElementById("ballInitialX").value);
320
+ const y = parseFloat(document.getElementById("ballInitialY").value);
321
+ const radius = parseFloat(document.getElementById("ballRadius").value);
322
+ const restitution = parseFloat(document.getElementById("ballRestitution").value);
323
+ const friction = parseFloat(document.getElementById("ballFriction").value);
324
+ const color = document.getElementById("ballColor").value || getRandomColor();
325
+ const ball = Bodies.circle(x, y, radius, { restitution, friction, render: { fillStyle: color } });
326
+ ball.elementType = "bouncingBall";
327
+ ball.customOptions = { x, y, radius, restitution, friction, color };
328
+ World.add(world, ball);
329
+ }
330
+ function addPendulum(){
331
+ const pivotX = parseFloat(document.getElementById("pendulumPivotX").value);
332
+ const pivotY = parseFloat(document.getElementById("pendulumPivotY").value);
333
+ const bobRadius = parseFloat(document.getElementById("pendulumBobRadius").value);
334
+ const pendulumLength = parseFloat(document.getElementById("pendulumLength").value);
335
+ const stiffness = parseFloat(document.getElementById("pendulumStiffness").value);
336
+ const bobColor = document.getElementById("pendulumBobColor").value || "#ff0000";
337
+ const bob = Bodies.circle(pivotX, pivotY+pendulumLength, bobRadius, { restitution: 1, density: 0.005, render: { fillStyle: bobColor } });
338
+ bob.elementType = "pendulum";
339
+ bob.customOptions = { pivotX, pivotY, bobRadius, pendulumLength, stiffness, bobColor };
340
+ const pendulumConstraint = Constraint.create({
341
+ pointA: { x: pivotX, y: pivotY },
342
+ bodyB: bob,
343
+ length: pendulumLength,
344
+ stiffness: stiffness,
345
+ render: { strokeStyle: '#000', lineWidth: 2 }
346
+ });
347
+ World.add(world, [bob, pendulumConstraint]);
348
+ }
349
+ function addProjectile(){
350
+ const x = parseFloat(document.getElementById("projectileInitialX").value);
351
+ const y = parseFloat(document.getElementById("projectileInitialY").value);
352
+ const radius = parseFloat(document.getElementById("projectileRadius").value);
353
+ const velX = parseFloat(document.getElementById("projectileVelX").value);
354
+ const velY = parseFloat(document.getElementById("projectileVelY").value);
355
+ const color = document.getElementById("projectileColor").value || getRandomColor();
356
+ const proj = Bodies.circle(x, y, radius, { restitution: 0.8, frictionAir: 0.001, render: { fillStyle: color } });
357
+ proj.elementType = "projectile";
358
+ proj.customOptions = { x, y, radius, velX, velY, color };
359
+ Body.setVelocity(proj, { x: velX, y: velY });
360
+ World.add(world, proj);
361
+ }
362
+ function addInclinedPlane(){
363
+ // Do bodies: ek ramp (static) aur ek block.
364
+ const rampWidth = parseFloat(document.getElementById("rampWidth").value);
365
+ const rampHeight = parseFloat(document.getElementById("rampHeight").value);
366
+ const angleDeg = parseFloat(document.getElementById("rampAngle").value);
367
+ const angle = angleDeg * Math.PI/180;
368
+ const rampX = parseFloat(document.getElementById("rampX").value);
369
+ const rampY = parseFloat(document.getElementById("rampY").value);
370
+ const rampColor = document.getElementById("rampColor").value || "#8e44ad";
371
+ const ramp = Bodies.rectangle(rampX, rampY, rampWidth, rampHeight, {
372
+ isStatic: true,
373
+ angle: angle,
374
+ render: { fillStyle: rampColor }
375
+ });
376
+ ramp.elementType = "inclinedPlane_ramp";
377
+ ramp.customOptions = { rampWidth, rampHeight, angleDeg, rampX, rampY, rampColor };
378
+ const blockWidth = parseFloat(document.getElementById("blockWidth").value);
379
+ const blockHeight = parseFloat(document.getElementById("blockHeight").value);
380
+ const blockFriction = parseFloat(document.getElementById("blockFriction").value);
381
+ const blockColor = document.getElementById("blockColor").value || "#1abc9c";
382
+ const block = Bodies.rectangle(rampX - rampWidth/4, rampY - 50, blockWidth, blockHeight, {
383
+ friction: blockFriction,
384
+ render: { fillStyle: blockColor }
385
+ });
386
+ block.elementType = "inclinedPlane_block";
387
+ block.customOptions = { blockWidth, blockHeight, blockFriction, blockColor };
388
+ World.add(world, [ramp, block]);
389
+ }
390
+ function addSpringMass(){
391
+ const massRadius = parseFloat(document.getElementById("springMassRadius").value);
392
+ const massRestitution = parseFloat(document.getElementById("springMassRestitution").value);
393
+ const fixedPointX = parseFloat(document.getElementById("fixedPointX").value);
394
+ const fixedPointY = parseFloat(document.getElementById("fixedPointY").value);
395
+ const springLength = parseFloat(document.getElementById("springLength").value);
396
+ const springStiffness = parseFloat(document.getElementById("springStiffness").value);
397
+ const massColor = document.getElementById("springMassColor").value || getRandomColor();
398
+ const mass = Bodies.circle(fixedPointX, fixedPointY+springLength, massRadius, {
399
+ restitution: massRestitution,
400
+ density: 0.004,
401
+ render: { fillStyle: massColor }
402
+ });
403
+ mass.elementType = "springMass";
404
+ mass.customOptions = { massRadius, massRestitution, fixedPointX, fixedPointY, springLength, springStiffness, massColor };
405
+ mass.fixedPoint = { x: fixedPointX, y: fixedPointY };
406
+ const spring = Constraint.create({
407
+ pointA: { x: fixedPointX, y: fixedPointY },
408
+ bodyB: mass,
409
+ length: springLength,
410
+ stiffness: springStiffness,
411
+ damping: 0.05,
412
+ render: { strokeStyle: '#000', lineWidth: 2 }
413
+ });
414
+ World.add(world, [mass, spring]);
415
+ }
416
+ document.getElementById('addElement').addEventListener('click', function(){
417
+ const selected = document.getElementById('simulationSelect').value;
418
+ if(selected === 'bouncingBall') addBouncingBall();
419
+ else if(selected === 'pendulum') addPendulum();
420
+ else if(selected === 'projectile') addProjectile();
421
+ else if(selected === 'inclinedPlane') addInclinedPlane();
422
+ else if(selected === 'springMass') addSpringMass();
423
+ });
424
+ document.getElementById('reset').addEventListener('click', function(){
425
+ World.clear(world);
426
+ Engine.clear(engine);
427
+ // Re-create boundaries on reset
428
+ updateBoundaries();
429
+ mouse = Mouse.create(render.canvas);
430
+ mouseConstraint = MouseConstraint.create(engine, { mouse: mouse, constraint: { stiffness: 0.2, render: { visible: false } } });
431
+ World.add(world, mouseConstraint);
432
+ render.mouse = mouse;
433
+ hideEditPanel();
434
+ hideConnectionPanel();
435
+ hideConstraintEditPanel();
436
+ });
437
+
438
+ /* ---------- Edit Panel Functions (Double–Click to Open) ---------- */
439
+ function openEditPanel(body) {
440
+ selectedBody = body;
441
+ let html = `<h3>Edit Element</h3>
442
+ <label for="editPosX">Position X:</label>
443
+ <input type="number" id="editPosX" value="${body.position.x.toFixed(2)}">
444
+ <label for="editPosY">Position Y:</label>
445
+ <input type="number" id="editPosY" value="${body.position.y.toFixed(2)}">
446
+ <label for="editAngle">Angle (radians):</label>
447
+ <input type="number" id="editAngle" value="${body.angle.toFixed(2)}">
448
+ <label for="editColor">Color:</label>
449
+ <input type="color" id="editColor" value="${body.render.fillStyle || '#ffffff'}">`;
450
+ if(body.elementType === "bouncingBall"){
451
+ const opts = body.customOptions;
452
+ html += `<label for="editBallRadius">Radius:</label>
453
+ <input type="number" id="editBallRadius" value="${opts.radius}">
454
+ <label for="editBallRestitution">Restitution:</label>
455
+ <input type="number" id="editBallRestitution" value="${opts.restitution}" step="0.1" min="0" max="1">
456
+ <label for="editBallFriction">Friction:</label>
457
+ <input type="number" id="editBallFriction" value="${opts.friction}" step="0.001" min="0" max="1">`;
458
+ } else if(body.elementType === "pendulum"){
459
+ const opts = body.customOptions;
460
+ html += `<label for="editPendulumPivotX">Pivot X:</label>
461
+ <input type="number" id="editPendulumPivotX" value="${opts.pivotX}">
462
+ <label for="editPendulumPivotY">Pivot Y:</label>
463
+ <input type="number" id="editPendulumPivotY" value="${opts.pivotY}">
464
+ <label for="editPendulumBobRadius">Bob Radius:</label>
465
+ <input type="number" id="editPendulumBobRadius" value="${opts.bobRadius}">
466
+ <label for="editPendulumLength">Length:</label>
467
+ <input type="number" id="editPendulumLength" value="${opts.pendulumLength}">
468
+ <label for="editPendulumStiffness">Stiffness:</label>
469
+ <input type="number" id="editPendulumStiffness" value="${opts.stiffness}" step="0.1" min="0" max="1">
470
+ <label for="editPendulumBobColor">Bob Color:</label>
471
+ <input type="color" id="editPendulumBobColor" value="${opts.bobColor}">`;
472
+ } else if(body.elementType === "projectile"){
473
+ const opts = body.customOptions;
474
+ html += `<label for="editProjectileRadius">Radius:</label>
475
+ <input type="number" id="editProjectileRadius" value="${opts.radius}">
476
+ <label for="editProjectileVelX">Velocity X:</label>
477
+ <input type="number" id="editProjectileVelX" value="${opts.velX}">
478
+ <label for="editProjectileVelY">Velocity Y:</label>
479
+ <input type="number" id="editProjectileVelY" value="${opts.velY}">`;
480
+ } else if(body.elementType === "inclinedPlane_ramp"){
481
+ const opts = body.customOptions;
482
+ html += `<label for="editRampWidth">Ramp Width:</label>
483
+ <input type="number" id="editRampWidth" value="${opts.rampWidth}">
484
+ <label for="editRampHeight">Ramp Height:</label>
485
+ <input type="number" id="editRampHeight" value="${opts.rampHeight}">
486
+ <label for="editRampAngle">Ramp Angle (°):</label>
487
+ <input type="number" id="editRampAngle" value="${opts.angleDeg}">
488
+ <label for="editRampX">Ramp X:</label>
489
+ <input type="number" id="editRampX" value="${opts.rampX}">
490
+ <label for="editRampY">Ramp Y:</label>
491
+ <input type="number" id="editRampY" value="${opts.rampY}">
492
+ <label for="editRampColor">Ramp Color:</label>
493
+ <input type="color" id="editRampColor" value="${opts.rampColor}">`;
494
+ } else if(body.elementType === "inclinedPlane_block"){
495
+ const opts = body.customOptions;
496
+ html += `<label for="editBlockWidth">Block Width:</label>
497
+ <input type="number" id="editBlockWidth" value="${opts.blockWidth}">
498
+ <label for="editBlockHeight">Block Height:</label>
499
+ <input type="number" id="editBlockHeight" value="${opts.blockHeight}">
500
+ <label for="editBlockFriction">Block Friction:</label>
501
+ <input type="number" id="editBlockFriction" value="${opts.blockFriction}" step="0.01" min="0" max="1">
502
+ <label for="editBlockColor">Block Color:</label>
503
+ <input type="color" id="editBlockColor" value="${opts.blockColor}">`;
504
+ } else if(body.elementType === "springMass"){
505
+ const opts = body.customOptions;
506
+ html += `<label for="editSpringMassRadius">Mass Radius:</label>
507
+ <input type="number" id="editSpringMassRadius" value="${opts.massRadius}">
508
+ <label for="editSpringMassRestitution">Restitution:</label>
509
+ <input type="number" id="editSpringMassRestitution" value="${opts.massRestitution}" step="0.1" min="0" max="1">
510
+ <label for="editFixedPointX">Fixed X:</label>
511
+ <input type="number" id="editFixedPointX" value="${opts.fixedPointX}">
512
+ <label for="editFixedPointY">Fixed Y:</label>
513
+ <input type="number" id="editFixedPointY" value="${opts.fixedPointY}">
514
+ <label for="editSpringLength">Spring Length:</label>
515
+ <input type="number" id="editSpringLength" value="${opts.springLength}">
516
+ <label for="editSpringStiffness">Spring Stiffness:</label>
517
+ <input type="number" id="editSpringStiffness" value="${opts.springStiffness}" step="0.01" min="0" max="1">
518
+ <label for="editSpringMassColor">Mass Color:</label>
519
+ <input type="color" id="editSpringMassColor" value="${opts.massColor}">`;
520
+ }
521
+ html += `<div style="margin-top:10px;">
522
+ <button id="updateElement">Update</button>
523
+ <button id="deleteElement">Delete</button>
524
+ </div>`;
525
+ editPanel.innerHTML = html;
526
+ editPanel.style.display = "block";
527
+ document.getElementById("updateElement").addEventListener("click", updateElementFromEditPanel);
528
+ document.getElementById("deleteElement").addEventListener("click", function(){
529
+ World.remove(world, selectedBody);
530
+ hideEditPanel();
531
+ });
532
+ }
533
+ function hideEditPanel() {
534
+ editPanel.style.display = "none";
535
+ selectedBody = null;
536
+ }
537
+ function updateElementFromEditPanel(){
538
+ if(!selectedBody) return;
539
+ const newX = parseFloat(document.getElementById("editPosX").value);
540
+ const newY = parseFloat(document.getElementById("editPosY").value);
541
+ const newAngle = parseFloat(document.getElementById("editAngle").value);
542
+ const newColor = document.getElementById("editColor").value;
543
+ Body.setPosition(selectedBody, { x: newX, y: newY });
544
+ Body.setAngle(selectedBody, newAngle);
545
+ selectedBody.render.fillStyle = newColor;
546
+ if(selectedBody.elementType === "bouncingBall"){
547
+ const oldRadius = selectedBody.circleRadius;
548
+ const newRadius = parseFloat(document.getElementById("editBallRadius").value);
549
+ const newRestitution = parseFloat(document.getElementById("editBallRestitution").value);
550
+ const newFriction = parseFloat(document.getElementById("editBallFriction").value);
551
+ if(newRadius && oldRadius && newRadius !== oldRadius){
552
+ const scaleFactor = newRadius / oldRadius;
553
+ Body.scale(selectedBody, scaleFactor, scaleFactor);
554
+ }
555
+ selectedBody.restitution = newRestitution;
556
+ selectedBody.friction = newFriction;
557
+ selectedBody.customOptions = { x: newX, y: newY, radius: newRadius, restitution: newRestitution, friction: newFriction, color: newColor };
558
+ }
559
+ // (Update code for other types as needed...)
560
+ hideEditPanel();
561
+ }
562
+
563
+ // Open edit panel on double–click on an element
564
+ render.canvas.addEventListener("dblclick", function(event){
565
+ const rect = render.canvas.getBoundingClientRect();
566
+ const mousePos = { x: event.clientX - rect.left, y: event.clientY - rect.top };
567
+ const bodies = Matter.Composite.allBodies(world);
568
+ const clicked = Matter.Query.point(bodies, mousePos);
569
+ if(clicked.length > 0){
570
+ openEditPanel(clicked[0]);
571
+ } else {
572
+ hideEditPanel();
573
+ }
574
+ });
575
+
576
+ /* ---------- Constraint & Connection Panels (Same as previous example) ---------- */
577
+ document.getElementById('cancelConn').addEventListener('click', function(){
578
+ connectionPanel.style.display = "none";
579
+ attachMode = false;
580
+ attachFrom = null;
581
+ });
582
+ Events.on(mouseConstraint, 'mouseup', function(event){
583
+ const mousePos = event.mouse.position;
584
+ const bodies = Matter.Composite.allBodies(world);
585
+ const clickedBodies = Matter.Query.point(bodies, mousePos);
586
+ if(clickedBodies.length > 0){
587
+ const clickedBody = clickedBodies[0];
588
+ if(attachMode && attachFrom && clickedBody !== attachFrom){
589
+ const connType = document.getElementById('connType').value;
590
+ let sourceEndpoint = "mass";
591
+ if(attachFrom.elementType === "springMass"){
592
+ sourceEndpoint = document.getElementById('sourceEndpoint').value;
593
+ }
594
+ let targetEndpoint = "mass";
595
+ if(clickedBody.elementType === "springMass"){
596
+ targetEndpoint = prompt("Target springMass: 'fixed' ya 'mass' (default mass):", "mass") || "mass";
597
+ if(targetEndpoint !== "fixed") { targetEndpoint = "mass"; }
598
+ }
599
+ let pointA = { x: 0, y: 0 }, bodyA = attachFrom;
600
+ if(attachFrom.elementType === "springMass" && sourceEndpoint === "fixed"){
601
+ bodyA = null;
602
+ pointA = attachFrom.fixedPoint;
603
+ }
604
+ let pointB = { x: 0, y: 0 }, bodyB = clickedBody;
605
+ if(clickedBody.elementType === "springMass" && targetEndpoint === "fixed"){
606
+ bodyB = null;
607
+ pointB = clickedBody.fixedPoint || { x: clickedBody.position.x, y: clickedBody.position.y };
608
+ }
609
+ let posA = bodyA ? attachFrom.position : pointA;
610
+ let posB = bodyB ? clickedBody.position : pointB;
611
+ let dx = posB.x - posA.x, dy = posB.y - posA.y;
612
+ let length = Math.sqrt(dx*dx+dy*dy);
613
+ let stiffness = (connType === "spring") ? 0.05 : 1;
614
+ const newConstraint = Constraint.create({
615
+ bodyA: bodyA,
616
+ pointA: pointA,
617
+ bodyB: bodyB,
618
+ pointB: pointB,
619
+ length: length,
620
+ stiffness: stiffness,
621
+ render: { strokeStyle: '#000', lineWidth: 2 }
622
+ });
623
+ World.add(world, newConstraint);
624
+ attachMode = false;
625
+ attachFrom = null;
626
+ connectionPanel.style.display = "none";
627
+ alert("Attachment created using " + connType + " connection.");
628
+ }
629
+ } else {
630
+ const constraints = Matter.Composite.allConstraints(world);
631
+ for(let cons of constraints){
632
+ let posA = cons.bodyA ? { x: cons.bodyA.position.x + cons.pointA.x, y: cons.bodyA.position.y + cons.pointA.y } : cons.pointA;
633
+ let posB = cons.bodyB ? { x: cons.bodyB.position.x + cons.pointB.x, y: cons.bodyB.position.y + cons.pointB.y } : cons.pointB;
634
+ let dist = distanceToSegment(mousePos, posA, posB);
635
+ if(dist < 5){
636
+ showConstraintEditPanel(cons);
637
+ return;
638
+ }
639
+ }
640
+ hideConstraintEditPanel();
641
+ }
642
+ });
643
+ function distanceToSegment(p, v, w){
644
+ let l2 = (w.x-v.x)**2 + (w.y-v.y)**2;
645
+ if(l2 === 0) return Math.hypot(p.x-v.x, p.y-v.y);
646
+ let t = ((p.x-v.x)*(w.x-v.x) + (p.y-v.y)*(w.y-v.y)) / l2;
647
+ t = Math.max(0, Math.min(1, t));
648
+ let proj = { x: v.x + t*(w.x-v.x), y: v.y + t*(w.y-v.y) };
649
+ return Math.hypot(p.x-proj.x, p.y-proj.y);
650
+ }
651
+ const constraintEditPanel = document.getElementById('constraintEditPanel');
652
+ function showConstraintEditPanel(cons){
653
+ selectedConstraint = cons;
654
+ let posA = cons.bodyA ? { x: cons.bodyA.position.x + cons.pointA.x, y: cons.bodyA.position.y + cons.pointA.y } : cons.pointA;
655
+ let posB = cons.bodyB ? { x: cons.bodyB.position.x + cons.pointB.x, y: cons.bodyB.position.y + cons.pointB.y } : cons.pointB;
656
+ document.getElementById('consA_X').value = posA.x.toFixed(2);
657
+ document.getElementById('consA_Y').value = posA.y.toFixed(2);
658
+ document.getElementById('consB_X').value = posB.x.toFixed(2);
659
+ document.getElementById('consB_Y').value = posB.y.toFixed(2);
660
+ let connType = (cons.stiffness < 0.1) ? "spring" : "string";
661
+ document.getElementById('consType').value = connType;
662
+ constraintEditPanel.style.display = "block";
663
+ }
664
+ function hideConstraintEditPanel(){
665
+ constraintEditPanel.style.display = "none";
666
+ selectedConstraint = null;
667
+ }
668
+ document.getElementById('updateConstraint').addEventListener('click', function(){
669
+ if(selectedConstraint){
670
+ let aX = parseFloat(document.getElementById('consA_X').value);
671
+ let aY = parseFloat(document.getElementById('consA_Y').value);
672
+ let bX = parseFloat(document.getElementById('consB_X').value);
673
+ let bY = parseFloat(document.getElementById('consB_Y').value);
674
+ if(!selectedConstraint.bodyA) { selectedConstraint.pointA = { x: aX, y: aY }; }
675
+ if(!selectedConstraint.bodyB) { selectedConstraint.pointB = { x: bX, y: bY }; }
676
+ let connType = document.getElementById('consType').value;
677
+ selectedConstraint.stiffness = (connType === "spring") ? 0.05 : 1;
678
+ hideConstraintEditPanel();
679
+ }
680
+ });
681
+ document.getElementById('deleteConstraint').addEventListener('click', function(){
682
+ if(selectedConstraint){
683
+ World.remove(world, selectedConstraint);
684
+ hideConstraintEditPanel();
685
+ }
686
+ });
687
+
688
+ // Window resize event: update renderer and boundaries
689
+ window.addEventListener('resize', function(){
690
+ Render.lookAt(render, { min: { x: 0, y: 0 }, max: { x: window.innerWidth, y: window.innerHeight } });
691
+ updateBoundaries();
692
+ });
693
+ </script>
694
+ </body>
695
  </html>