gpue commited on
Commit
375d9f7
·
1 Parent(s): 14eddff

Add touch controls for camera manipulation in mujoco_server.py

Browse files

- Implemented touch event listeners for camera rotation and pinch-to-zoom functionality.
- Enhanced user interaction by allowing single touch for rotation and dual touch for zooming.
- Added logic to handle touch movements and reset states for improved user experience.

Files changed (1) hide show
  1. mujoco_server.py +53 -0
mujoco_server.py CHANGED
@@ -1219,6 +1219,7 @@ def index():
1219
 
1220
  viewport.oncontextmenu = (e) => e.preventDefault();
1221
 
 
1222
  viewport.onmousedown = (e) => {
1223
  isDragging = true;
1224
  lastX = e.clientX;
@@ -1244,6 +1245,58 @@ def index():
1244
  send('camera', {action: 'zoom', dz: e.deltaY});
1245
  };
1246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1247
  // Connect on load
1248
  connect();
1249
  </script>
 
1219
 
1220
  viewport.oncontextmenu = (e) => e.preventDefault();
1221
 
1222
+ // Mouse controls
1223
  viewport.onmousedown = (e) => {
1224
  isDragging = true;
1225
  lastX = e.clientX;
 
1245
  send('camera', {action: 'zoom', dz: e.deltaY});
1246
  };
1247
 
1248
+ // Touch controls for camera rotation and pinch-to-zoom
1249
+ let touchStartX, touchStartY;
1250
+ let lastPinchDist = null;
1251
+
1252
+ function getTouchDistance(touches) {
1253
+ const dx = touches[0].clientX - touches[1].clientX;
1254
+ const dy = touches[0].clientY - touches[1].clientY;
1255
+ return Math.sqrt(dx * dx + dy * dy);
1256
+ }
1257
+
1258
+ viewport.addEventListener('touchstart', (e) => {
1259
+ if (e.touches.length === 1) {
1260
+ // Single touch - rotation
1261
+ touchStartX = e.touches[0].clientX;
1262
+ touchStartY = e.touches[0].clientY;
1263
+ lastPinchDist = null;
1264
+ } else if (e.touches.length === 2) {
1265
+ // Two touches - pinch zoom
1266
+ lastPinchDist = getTouchDistance(e.touches);
1267
+ }
1268
+ }, {passive: true});
1269
+
1270
+ viewport.addEventListener('touchmove', (e) => {
1271
+ e.preventDefault();
1272
+ if (e.touches.length === 1 && lastPinchDist === null) {
1273
+ // Single touch drag - rotate camera
1274
+ const dx = e.touches[0].clientX - touchStartX;
1275
+ const dy = e.touches[0].clientY - touchStartY;
1276
+ touchStartX = e.touches[0].clientX;
1277
+ touchStartY = e.touches[0].clientY;
1278
+ send('camera', {action: 'rotate', dx, dy});
1279
+ } else if (e.touches.length === 2 && lastPinchDist !== null) {
1280
+ // Pinch zoom
1281
+ const dist = getTouchDistance(e.touches);
1282
+ const delta = lastPinchDist - dist;
1283
+ lastPinchDist = dist;
1284
+ // Scale delta for smoother zoom
1285
+ send('camera', {action: 'zoom', dz: delta * 3});
1286
+ }
1287
+ }, {passive: false});
1288
+
1289
+ viewport.addEventListener('touchend', (e) => {
1290
+ if (e.touches.length < 2) {
1291
+ lastPinchDist = null;
1292
+ }
1293
+ if (e.touches.length === 1) {
1294
+ // Reset for single finger after pinch
1295
+ touchStartX = e.touches[0].clientX;
1296
+ touchStartY = e.touches[0].clientY;
1297
+ }
1298
+ }, {passive: true});
1299
+
1300
  // Connect on load
1301
  connect();
1302
  </script>