@tsdraw/core 0.8.3 → 0.8.5
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 +117 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -19
- package/dist/index.d.ts +61 -19
- package/dist/index.js +113 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -249,8 +249,13 @@ function setViewport(viewport, updater) {
|
|
|
249
249
|
function panViewport(viewport, dx, dy) {
|
|
250
250
|
return { ...viewport, x: viewport.x + dx, y: viewport.y + dy };
|
|
251
251
|
}
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
var DEFAULT_ZOOM_RANGE = { min: 0.1, max: 4 };
|
|
253
|
+
function clampZoom(zoom, range) {
|
|
254
|
+
const { min, max } = range ?? DEFAULT_ZOOM_RANGE;
|
|
255
|
+
return Math.max(min, Math.min(max, zoom));
|
|
256
|
+
}
|
|
257
|
+
function zoomViewport(viewport, factor, centerX, centerY, zoomRange) {
|
|
258
|
+
const zoom = clampZoom(viewport.zoom * factor, zoomRange);
|
|
254
259
|
if (centerX == null || centerY == null) {
|
|
255
260
|
return { ...viewport, zoom };
|
|
256
261
|
}
|
|
@@ -260,6 +265,90 @@ function zoomViewport(viewport, factor, centerX, centerY) {
|
|
|
260
265
|
return { x, y, zoom };
|
|
261
266
|
}
|
|
262
267
|
|
|
268
|
+
// src/canvas/cameraPan.ts
|
|
269
|
+
var VELOCITY_LERP_FACTOR = 0.5;
|
|
270
|
+
var VELOCITY_ZERO_THRESHOLD = 0.01;
|
|
271
|
+
function beginCameraPan(viewport, screenX, screenY) {
|
|
272
|
+
return {
|
|
273
|
+
initialViewportX: viewport.x,
|
|
274
|
+
initialViewportY: viewport.y,
|
|
275
|
+
originScreenX: screenX,
|
|
276
|
+
originScreenY: screenY,
|
|
277
|
+
velocityX: 0,
|
|
278
|
+
velocityY: 0,
|
|
279
|
+
previousScreenX: screenX,
|
|
280
|
+
previousScreenY: screenY,
|
|
281
|
+
lastMoveTime: performance.now()
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function moveCameraPan(session, currentScreenX, currentScreenY) {
|
|
285
|
+
const now = performance.now();
|
|
286
|
+
const elapsed = now - session.lastMoveTime;
|
|
287
|
+
if (elapsed > 0) {
|
|
288
|
+
const moveDx = currentScreenX - session.previousScreenX;
|
|
289
|
+
const moveDy = currentScreenY - session.previousScreenY;
|
|
290
|
+
const moveLen = Math.hypot(moveDx, moveDy);
|
|
291
|
+
if (moveLen > 0) {
|
|
292
|
+
const dirX = moveDx / moveLen;
|
|
293
|
+
const dirY = moveDy / moveLen;
|
|
294
|
+
const speed = moveLen / elapsed;
|
|
295
|
+
session.velocityX += (dirX * speed - session.velocityX) * VELOCITY_LERP_FACTOR;
|
|
296
|
+
session.velocityY += (dirY * speed - session.velocityY) * VELOCITY_LERP_FACTOR;
|
|
297
|
+
}
|
|
298
|
+
if (Math.abs(session.velocityX) < VELOCITY_ZERO_THRESHOLD) session.velocityX = 0;
|
|
299
|
+
if (Math.abs(session.velocityY) < VELOCITY_ZERO_THRESHOLD) session.velocityY = 0;
|
|
300
|
+
}
|
|
301
|
+
session.previousScreenX = currentScreenX;
|
|
302
|
+
session.previousScreenY = currentScreenY;
|
|
303
|
+
session.lastMoveTime = now;
|
|
304
|
+
return {
|
|
305
|
+
x: session.initialViewportX + (currentScreenX - session.originScreenX),
|
|
306
|
+
y: session.initialViewportY + (currentScreenY - session.originScreenY)
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
var SLIDE_FRICTION = 0.92;
|
|
310
|
+
var SLIDE_MIN_SPEED = 0.01;
|
|
311
|
+
var SLIDE_MAX_SPEED = 2;
|
|
312
|
+
var SLIDE_MIN_VELOCITY_TO_START = 0.1;
|
|
313
|
+
function startCameraSlide(session, applyPan, onFrame, slideOptions) {
|
|
314
|
+
const friction = slideOptions?.friction ?? SLIDE_FRICTION;
|
|
315
|
+
const timeSinceLastMove = performance.now() - session.lastMoveTime;
|
|
316
|
+
const FRAME_DURATION = 16;
|
|
317
|
+
const decayFactor = Math.pow(1 - VELOCITY_LERP_FACTOR, timeSinceLastMove / FRAME_DURATION);
|
|
318
|
+
const effectiveVx = session.velocityX * decayFactor;
|
|
319
|
+
const effectiveVy = session.velocityY * decayFactor;
|
|
320
|
+
const speed = Math.hypot(effectiveVx, effectiveVy);
|
|
321
|
+
const clampedSpeed = Math.min(speed, SLIDE_MAX_SPEED);
|
|
322
|
+
if (clampedSpeed < SLIDE_MIN_VELOCITY_TO_START) return null;
|
|
323
|
+
const dirX = effectiveVx / speed;
|
|
324
|
+
const dirY = effectiveVy / speed;
|
|
325
|
+
let currentSpeed = clampedSpeed;
|
|
326
|
+
let lastTime = performance.now();
|
|
327
|
+
let rafId = 0;
|
|
328
|
+
const tick = () => {
|
|
329
|
+
const now = performance.now();
|
|
330
|
+
const elapsed = now - lastTime;
|
|
331
|
+
lastTime = now;
|
|
332
|
+
applyPan(dirX * currentSpeed * elapsed, dirY * currentSpeed * elapsed);
|
|
333
|
+
onFrame();
|
|
334
|
+
currentSpeed *= friction;
|
|
335
|
+
if (currentSpeed < SLIDE_MIN_SPEED) {
|
|
336
|
+
rafId = 0;
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
rafId = requestAnimationFrame(tick);
|
|
340
|
+
};
|
|
341
|
+
rafId = requestAnimationFrame(tick);
|
|
342
|
+
return {
|
|
343
|
+
stop() {
|
|
344
|
+
if (rafId !== 0) {
|
|
345
|
+
cancelAnimationFrame(rafId);
|
|
346
|
+
rafId = 0;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
263
352
|
// src/utils/colors.ts
|
|
264
353
|
var DARK_COLORS = {
|
|
265
354
|
black: "#f0f0f0",
|
|
@@ -1492,16 +1581,29 @@ var HandIdleState = class extends StateNode {
|
|
|
1492
1581
|
// src/tools/hand/states/HandDraggingState.ts
|
|
1493
1582
|
var HandDraggingState = class extends StateNode {
|
|
1494
1583
|
static id = "hand_dragging";
|
|
1584
|
+
panSession = null;
|
|
1585
|
+
onEnter(info) {
|
|
1586
|
+
const downInfo = info;
|
|
1587
|
+
const screenX = downInfo?.screenX ?? 0;
|
|
1588
|
+
const screenY = downInfo?.screenY ?? 0;
|
|
1589
|
+
this.panSession = beginCameraPan(this.editor.viewport, screenX, screenY);
|
|
1590
|
+
}
|
|
1495
1591
|
onPointerMove(info) {
|
|
1496
|
-
|
|
1497
|
-
const
|
|
1498
|
-
const
|
|
1499
|
-
|
|
1500
|
-
this.editor.
|
|
1592
|
+
if (!this.panSession) return;
|
|
1593
|
+
const screenX = info?.screenX ?? 0;
|
|
1594
|
+
const screenY = info?.screenY ?? 0;
|
|
1595
|
+
const target = moveCameraPan(this.panSession, screenX, screenY);
|
|
1596
|
+
this.editor.setViewport({ x: target.x, y: target.y });
|
|
1597
|
+
}
|
|
1598
|
+
getPanSession() {
|
|
1599
|
+
return this.panSession;
|
|
1501
1600
|
}
|
|
1502
1601
|
onPointerUp() {
|
|
1503
1602
|
this.ctx.transition("hand_idle");
|
|
1504
1603
|
}
|
|
1604
|
+
onExit() {
|
|
1605
|
+
this.panSession = null;
|
|
1606
|
+
}
|
|
1505
1607
|
onCancel() {
|
|
1506
1608
|
this.ctx.transition("hand_idle");
|
|
1507
1609
|
}
|
|
@@ -1615,7 +1717,7 @@ var Editor = class {
|
|
|
1615
1717
|
historyBatchChanged = false;
|
|
1616
1718
|
// Creates a new editor instance with the given options (with defaults if not provided)
|
|
1617
1719
|
constructor(opts = {}) {
|
|
1618
|
-
this.options = { dragDistanceSquared: opts.dragDistanceSquared ?? DRAG_DISTANCE_SQUARED };
|
|
1720
|
+
this.options = { dragDistanceSquared: opts.dragDistanceSquared ?? DRAG_DISTANCE_SQUARED, zoomRange: opts.zoomRange };
|
|
1619
1721
|
this.lastDocumentSnapshot = this.getDocumentSnapshot();
|
|
1620
1722
|
this.store.listen(() => {
|
|
1621
1723
|
this.captureDocumentHistory();
|
|
@@ -1729,7 +1831,7 @@ var Editor = class {
|
|
|
1729
1831
|
this.viewport = {
|
|
1730
1832
|
x: partial.x ?? this.viewport.x,
|
|
1731
1833
|
y: partial.y ?? this.viewport.y,
|
|
1732
|
-
zoom:
|
|
1834
|
+
zoom: clampZoom(rawZoom, this.options.zoomRange)
|
|
1733
1835
|
};
|
|
1734
1836
|
this.emitChange();
|
|
1735
1837
|
}
|
|
@@ -1740,7 +1842,7 @@ var Editor = class {
|
|
|
1740
1842
|
});
|
|
1741
1843
|
}
|
|
1742
1844
|
zoomAt(factor, screenX, screenY) {
|
|
1743
|
-
this.viewport = zoomViewport(this.viewport, factor, screenX, screenY);
|
|
1845
|
+
this.viewport = zoomViewport(this.viewport, factor, screenX, screenY, this.options.zoomRange);
|
|
1744
1846
|
this.emitChange();
|
|
1745
1847
|
}
|
|
1746
1848
|
deleteShapes(ids) {
|
|
@@ -2164,6 +2266,7 @@ exports.CanvasRenderer = CanvasRenderer;
|
|
|
2164
2266
|
exports.CircleDrawingState = CircleDrawingState;
|
|
2165
2267
|
exports.CircleIdleState = CircleIdleState;
|
|
2166
2268
|
exports.DEFAULT_COLORS = DEFAULT_COLORS;
|
|
2269
|
+
exports.DEFAULT_ZOOM_RANGE = DEFAULT_ZOOM_RANGE;
|
|
2167
2270
|
exports.DRAG_DISTANCE_SQUARED = DRAG_DISTANCE_SQUARED;
|
|
2168
2271
|
exports.DocumentStore = DocumentStore;
|
|
2169
2272
|
exports.ERASER_MARGIN = ERASER_MARGIN;
|
|
@@ -2186,11 +2289,13 @@ exports.ToolManager = ToolManager;
|
|
|
2186
2289
|
exports.applyMove = applyMove;
|
|
2187
2290
|
exports.applyResize = applyResize;
|
|
2188
2291
|
exports.applyRotation = applyRotation;
|
|
2292
|
+
exports.beginCameraPan = beginCameraPan;
|
|
2189
2293
|
exports.boundsContainPoint = boundsContainPoint;
|
|
2190
2294
|
exports.boundsIntersect = boundsIntersect;
|
|
2191
2295
|
exports.boundsOf = boundsOf;
|
|
2192
2296
|
exports.buildStartPositions = buildStartPositions;
|
|
2193
2297
|
exports.buildTransformSnapshots = buildTransformSnapshots;
|
|
2298
|
+
exports.clampZoom = clampZoom;
|
|
2194
2299
|
exports.closestOnSegment = closestOnSegment;
|
|
2195
2300
|
exports.createViewport = createViewport;
|
|
2196
2301
|
exports.decodeFirstPoint = decodeFirstPoint;
|
|
@@ -2206,6 +2311,7 @@ exports.getShapesInBounds = getShapesInBounds;
|
|
|
2206
2311
|
exports.getTopShapeAtPoint = getTopShapeAtPoint;
|
|
2207
2312
|
exports.isSelectTool = isSelectTool;
|
|
2208
2313
|
exports.minDistanceToPolyline = minDistanceToPolyline;
|
|
2314
|
+
exports.moveCameraPan = moveCameraPan;
|
|
2209
2315
|
exports.normalizeSelectionBounds = normalizeSelectionBounds;
|
|
2210
2316
|
exports.padBounds = padBounds;
|
|
2211
2317
|
exports.pageToScreen = pageToScreen;
|
|
@@ -2220,6 +2326,7 @@ exports.segmentTouchesPolyline = segmentTouchesPolyline;
|
|
|
2220
2326
|
exports.setViewport = setViewport;
|
|
2221
2327
|
exports.shapePagePoints = shapePagePoints;
|
|
2222
2328
|
exports.sqDistance = sqDistance;
|
|
2329
|
+
exports.startCameraSlide = startCameraSlide;
|
|
2223
2330
|
exports.zoomViewport = zoomViewport;
|
|
2224
2331
|
//# sourceMappingURL=index.cjs.map
|
|
2225
2332
|
//# sourceMappingURL=index.cjs.map
|