@tsdraw/core 0.8.3 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -260,6 +260,89 @@ function zoomViewport(viewport, factor, centerX, centerY) {
260
260
  return { x, y, zoom };
261
261
  }
262
262
 
263
+ // src/canvas/cameraPan.ts
264
+ var VELOCITY_LERP_FACTOR = 0.5;
265
+ var VELOCITY_ZERO_THRESHOLD = 0.01;
266
+ function beginCameraPan(viewport, screenX, screenY) {
267
+ return {
268
+ initialViewportX: viewport.x,
269
+ initialViewportY: viewport.y,
270
+ originScreenX: screenX,
271
+ originScreenY: screenY,
272
+ velocityX: 0,
273
+ velocityY: 0,
274
+ previousScreenX: screenX,
275
+ previousScreenY: screenY,
276
+ lastMoveTime: performance.now()
277
+ };
278
+ }
279
+ function moveCameraPan(session, currentScreenX, currentScreenY) {
280
+ const now = performance.now();
281
+ const elapsed = now - session.lastMoveTime;
282
+ if (elapsed > 0) {
283
+ const moveDx = currentScreenX - session.previousScreenX;
284
+ const moveDy = currentScreenY - session.previousScreenY;
285
+ const moveLen = Math.hypot(moveDx, moveDy);
286
+ if (moveLen > 0) {
287
+ const dirX = moveDx / moveLen;
288
+ const dirY = moveDy / moveLen;
289
+ const speed = moveLen / elapsed;
290
+ session.velocityX += (dirX * speed - session.velocityX) * VELOCITY_LERP_FACTOR;
291
+ session.velocityY += (dirY * speed - session.velocityY) * VELOCITY_LERP_FACTOR;
292
+ }
293
+ if (Math.abs(session.velocityX) < VELOCITY_ZERO_THRESHOLD) session.velocityX = 0;
294
+ if (Math.abs(session.velocityY) < VELOCITY_ZERO_THRESHOLD) session.velocityY = 0;
295
+ }
296
+ session.previousScreenX = currentScreenX;
297
+ session.previousScreenY = currentScreenY;
298
+ session.lastMoveTime = now;
299
+ return {
300
+ x: session.initialViewportX + (currentScreenX - session.originScreenX),
301
+ y: session.initialViewportY + (currentScreenY - session.originScreenY)
302
+ };
303
+ }
304
+ var SLIDE_FRICTION = 0.92;
305
+ var SLIDE_MIN_SPEED = 0.01;
306
+ var SLIDE_MAX_SPEED = 2;
307
+ var SLIDE_MIN_VELOCITY_TO_START = 0.1;
308
+ function startCameraSlide(session, applyPan, onFrame) {
309
+ const timeSinceLastMove = performance.now() - session.lastMoveTime;
310
+ const FRAME_DURATION = 16;
311
+ const decayFactor = Math.pow(1 - VELOCITY_LERP_FACTOR, timeSinceLastMove / FRAME_DURATION);
312
+ const effectiveVx = session.velocityX * decayFactor;
313
+ const effectiveVy = session.velocityY * decayFactor;
314
+ const speed = Math.hypot(effectiveVx, effectiveVy);
315
+ const clampedSpeed = Math.min(speed, SLIDE_MAX_SPEED);
316
+ if (clampedSpeed < SLIDE_MIN_VELOCITY_TO_START) return null;
317
+ const dirX = effectiveVx / speed;
318
+ const dirY = effectiveVy / speed;
319
+ let currentSpeed = clampedSpeed;
320
+ let lastTime = performance.now();
321
+ let rafId = 0;
322
+ const tick = () => {
323
+ const now = performance.now();
324
+ const elapsed = now - lastTime;
325
+ lastTime = now;
326
+ applyPan(dirX * currentSpeed * elapsed, dirY * currentSpeed * elapsed);
327
+ onFrame();
328
+ currentSpeed *= SLIDE_FRICTION;
329
+ if (currentSpeed < SLIDE_MIN_SPEED) {
330
+ rafId = 0;
331
+ return;
332
+ }
333
+ rafId = requestAnimationFrame(tick);
334
+ };
335
+ rafId = requestAnimationFrame(tick);
336
+ return {
337
+ stop() {
338
+ if (rafId !== 0) {
339
+ cancelAnimationFrame(rafId);
340
+ rafId = 0;
341
+ }
342
+ }
343
+ };
344
+ }
345
+
263
346
  // src/utils/colors.ts
264
347
  var DARK_COLORS = {
265
348
  black: "#f0f0f0",
@@ -1492,16 +1575,29 @@ var HandIdleState = class extends StateNode {
1492
1575
  // src/tools/hand/states/HandDraggingState.ts
1493
1576
  var HandDraggingState = class extends StateNode {
1494
1577
  static id = "hand_dragging";
1578
+ panSession = null;
1579
+ onEnter(info) {
1580
+ const downInfo = info;
1581
+ const screenX = downInfo?.screenX ?? 0;
1582
+ const screenY = downInfo?.screenY ?? 0;
1583
+ this.panSession = beginCameraPan(this.editor.viewport, screenX, screenY);
1584
+ }
1495
1585
  onPointerMove(info) {
1496
- const move = info ?? {};
1497
- const dx = move.screenDeltaX ?? 0;
1498
- const dy = move.screenDeltaY ?? 0;
1499
- if (dx === 0 && dy === 0) return;
1500
- this.editor.panBy(dx, dy);
1586
+ if (!this.panSession) return;
1587
+ const screenX = info?.screenX ?? 0;
1588
+ const screenY = info?.screenY ?? 0;
1589
+ const target = moveCameraPan(this.panSession, screenX, screenY);
1590
+ this.editor.setViewport({ x: target.x, y: target.y });
1591
+ }
1592
+ getPanSession() {
1593
+ return this.panSession;
1501
1594
  }
1502
1595
  onPointerUp() {
1503
1596
  this.ctx.transition("hand_idle");
1504
1597
  }
1598
+ onExit() {
1599
+ this.panSession = null;
1600
+ }
1505
1601
  onCancel() {
1506
1602
  this.ctx.transition("hand_idle");
1507
1603
  }
@@ -2186,6 +2282,7 @@ exports.ToolManager = ToolManager;
2186
2282
  exports.applyMove = applyMove;
2187
2283
  exports.applyResize = applyResize;
2188
2284
  exports.applyRotation = applyRotation;
2285
+ exports.beginCameraPan = beginCameraPan;
2189
2286
  exports.boundsContainPoint = boundsContainPoint;
2190
2287
  exports.boundsIntersect = boundsIntersect;
2191
2288
  exports.boundsOf = boundsOf;
@@ -2206,6 +2303,7 @@ exports.getShapesInBounds = getShapesInBounds;
2206
2303
  exports.getTopShapeAtPoint = getTopShapeAtPoint;
2207
2304
  exports.isSelectTool = isSelectTool;
2208
2305
  exports.minDistanceToPolyline = minDistanceToPolyline;
2306
+ exports.moveCameraPan = moveCameraPan;
2209
2307
  exports.normalizeSelectionBounds = normalizeSelectionBounds;
2210
2308
  exports.padBounds = padBounds;
2211
2309
  exports.pageToScreen = pageToScreen;
@@ -2220,6 +2318,7 @@ exports.segmentTouchesPolyline = segmentTouchesPolyline;
2220
2318
  exports.setViewport = setViewport;
2221
2319
  exports.shapePagePoints = shapePagePoints;
2222
2320
  exports.sqDistance = sqDistance;
2321
+ exports.startCameraSlide = startCameraSlide;
2223
2322
  exports.zoomViewport = zoomViewport;
2224
2323
  //# sourceMappingURL=index.cjs.map
2225
2324
  //# sourceMappingURL=index.cjs.map