@tsdraw/core 0.8.4 → 0.9.0
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 +119 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -4
- package/dist/index.d.ts +32 -4
- package/dist/index.js +117 -12
- 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
|
}
|
|
@@ -305,7 +310,8 @@ var SLIDE_FRICTION = 0.92;
|
|
|
305
310
|
var SLIDE_MIN_SPEED = 0.01;
|
|
306
311
|
var SLIDE_MAX_SPEED = 2;
|
|
307
312
|
var SLIDE_MIN_VELOCITY_TO_START = 0.1;
|
|
308
|
-
function startCameraSlide(session, applyPan, onFrame) {
|
|
313
|
+
function startCameraSlide(session, applyPan, onFrame, slideOptions) {
|
|
314
|
+
const friction = slideOptions?.friction ?? SLIDE_FRICTION;
|
|
309
315
|
const timeSinceLastMove = performance.now() - session.lastMoveTime;
|
|
310
316
|
const FRAME_DURATION = 16;
|
|
311
317
|
const decayFactor = Math.pow(1 - VELOCITY_LERP_FACTOR, timeSinceLastMove / FRAME_DURATION);
|
|
@@ -325,7 +331,7 @@ function startCameraSlide(session, applyPan, onFrame) {
|
|
|
325
331
|
lastTime = now;
|
|
326
332
|
applyPan(dirX * currentSpeed * elapsed, dirY * currentSpeed * elapsed);
|
|
327
333
|
onFrame();
|
|
328
|
-
currentSpeed *=
|
|
334
|
+
currentSpeed *= friction;
|
|
329
335
|
if (currentSpeed < SLIDE_MIN_SPEED) {
|
|
330
336
|
rafId = 0;
|
|
331
337
|
return;
|
|
@@ -366,9 +372,12 @@ function resolveThemeColor(colorStyle, theme) {
|
|
|
366
372
|
return DARK_COLORS[colorStyle] ?? lightThemeColor;
|
|
367
373
|
}
|
|
368
374
|
var CanvasRenderer = class {
|
|
369
|
-
|
|
375
|
+
_theme = "light";
|
|
376
|
+
get theme() {
|
|
377
|
+
return this._theme;
|
|
378
|
+
}
|
|
370
379
|
setTheme(theme) {
|
|
371
|
-
this.
|
|
380
|
+
this._theme = theme;
|
|
372
381
|
}
|
|
373
382
|
render(ctx, viewport, shapes) {
|
|
374
383
|
ctx.save();
|
|
@@ -386,7 +395,7 @@ var CanvasRenderer = class {
|
|
|
386
395
|
const width = (STROKE_WIDTHS[shape.props.size] ?? 3.5) * shape.props.scale;
|
|
387
396
|
const samples = flattenSegments(shape);
|
|
388
397
|
if (samples.length === 0) return;
|
|
389
|
-
const color = resolveThemeColor(shape.props.color, this.
|
|
398
|
+
const color = resolveThemeColor(shape.props.color, this._theme);
|
|
390
399
|
const fillStyle = shape.props.fill ?? "none";
|
|
391
400
|
if (shape.props.isClosed && fillStyle !== "none") {
|
|
392
401
|
this.paintClosedShapeFill(ctx, samples, color, fillStyle);
|
|
@@ -452,7 +461,7 @@ var CanvasRenderer = class {
|
|
|
452
461
|
ctx.fillStyle = color;
|
|
453
462
|
ctx.globalAlpha = 0.55;
|
|
454
463
|
} else if (fillStyle === "none") {
|
|
455
|
-
ctx.fillStyle = this.
|
|
464
|
+
ctx.fillStyle = this._theme === "dark" ? "#0f0f0f" : "#fafafa";
|
|
456
465
|
ctx.globalAlpha = 1;
|
|
457
466
|
} else {
|
|
458
467
|
ctx.fillStyle = color;
|
|
@@ -548,6 +557,102 @@ function getLineDash(dash, width) {
|
|
|
548
557
|
}
|
|
549
558
|
}
|
|
550
559
|
|
|
560
|
+
// src/canvas/backgroundRenderer.ts
|
|
561
|
+
var DEFAULT_SPACING = 20;
|
|
562
|
+
var DEFAULT_LINE_WIDTH = 0.5;
|
|
563
|
+
var DEFAULT_DOT_RADIUS = 1;
|
|
564
|
+
var DEFAULT_OPACITY = 0.25;
|
|
565
|
+
function resolvePresetPatternColor(colorLight, colorDark, theme) {
|
|
566
|
+
if (theme === "dark") return colorDark ?? colorLight ?? "#888888";
|
|
567
|
+
return colorLight ?? "#c0c0c0";
|
|
568
|
+
}
|
|
569
|
+
function visiblePageRect(viewport, canvasWidth, canvasHeight) {
|
|
570
|
+
return {
|
|
571
|
+
minX: (0 - viewport.x) / viewport.zoom,
|
|
572
|
+
minY: (0 - viewport.y) / viewport.zoom,
|
|
573
|
+
maxX: (canvasWidth - viewport.x) / viewport.zoom,
|
|
574
|
+
maxY: (canvasHeight - viewport.y) / viewport.zoom
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
function drawHorizontalLines(ctx, visible, spacing, lineWidth, color, opacity) {
|
|
578
|
+
const startY = Math.floor(visible.minY / spacing) * spacing;
|
|
579
|
+
ctx.save();
|
|
580
|
+
ctx.strokeStyle = color;
|
|
581
|
+
ctx.lineWidth = lineWidth / ctx.getTransform().a;
|
|
582
|
+
ctx.globalAlpha = opacity;
|
|
583
|
+
ctx.beginPath();
|
|
584
|
+
for (let y = startY; y <= visible.maxY; y += spacing) {
|
|
585
|
+
ctx.moveTo(visible.minX, y);
|
|
586
|
+
ctx.lineTo(visible.maxX, y);
|
|
587
|
+
}
|
|
588
|
+
ctx.stroke();
|
|
589
|
+
ctx.restore();
|
|
590
|
+
}
|
|
591
|
+
function drawGridLines(ctx, visible, spacing, lineWidth, color, opacity) {
|
|
592
|
+
const startX = Math.floor(visible.minX / spacing) * spacing;
|
|
593
|
+
const startY = Math.floor(visible.minY / spacing) * spacing;
|
|
594
|
+
const compensatedWidth = lineWidth / ctx.getTransform().a;
|
|
595
|
+
ctx.save();
|
|
596
|
+
ctx.strokeStyle = color;
|
|
597
|
+
ctx.lineWidth = compensatedWidth;
|
|
598
|
+
ctx.globalAlpha = opacity;
|
|
599
|
+
ctx.beginPath();
|
|
600
|
+
for (let x = startX; x <= visible.maxX; x += spacing) {
|
|
601
|
+
ctx.moveTo(x, visible.minY);
|
|
602
|
+
ctx.lineTo(x, visible.maxY);
|
|
603
|
+
}
|
|
604
|
+
for (let y = startY; y <= visible.maxY; y += spacing) {
|
|
605
|
+
ctx.moveTo(visible.minX, y);
|
|
606
|
+
ctx.lineTo(visible.maxX, y);
|
|
607
|
+
}
|
|
608
|
+
ctx.stroke();
|
|
609
|
+
ctx.restore();
|
|
610
|
+
}
|
|
611
|
+
function drawDotPattern(ctx, visible, spacing, dotRadius, color, opacity) {
|
|
612
|
+
const startX = Math.floor(visible.minX / spacing) * spacing;
|
|
613
|
+
const startY = Math.floor(visible.minY / spacing) * spacing;
|
|
614
|
+
const compensatedRadius = dotRadius / ctx.getTransform().a;
|
|
615
|
+
ctx.save();
|
|
616
|
+
ctx.fillStyle = color;
|
|
617
|
+
ctx.globalAlpha = opacity;
|
|
618
|
+
ctx.beginPath();
|
|
619
|
+
for (let x = startX; x <= visible.maxX; x += spacing) {
|
|
620
|
+
for (let y = startY; y <= visible.maxY; y += spacing) {
|
|
621
|
+
ctx.moveTo(x + compensatedRadius, y);
|
|
622
|
+
ctx.arc(x, y, compensatedRadius, 0, Math.PI * 2);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
ctx.fill();
|
|
626
|
+
ctx.restore();
|
|
627
|
+
}
|
|
628
|
+
function renderCanvasBackground(ctx, viewport, canvasWidth, canvasHeight, options, theme) {
|
|
629
|
+
if (!options || options.type === "blank") return;
|
|
630
|
+
if (options.type === "custom") {
|
|
631
|
+
options.render(ctx, viewport, canvasWidth, canvasHeight);
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
const spacing = options.spacing ?? DEFAULT_SPACING;
|
|
635
|
+
if (spacing <= 0) return;
|
|
636
|
+
const color = resolvePresetPatternColor(options.color, options.colorDark, theme);
|
|
637
|
+
const opacity = options.opacity ?? DEFAULT_OPACITY;
|
|
638
|
+
const visible = visiblePageRect(viewport, canvasWidth, canvasHeight);
|
|
639
|
+
ctx.save();
|
|
640
|
+
ctx.translate(viewport.x, viewport.y);
|
|
641
|
+
ctx.scale(viewport.zoom, viewport.zoom);
|
|
642
|
+
switch (options.type) {
|
|
643
|
+
case "lines":
|
|
644
|
+
drawHorizontalLines(ctx, visible, spacing, options.size ?? DEFAULT_LINE_WIDTH, color, opacity);
|
|
645
|
+
break;
|
|
646
|
+
case "grid":
|
|
647
|
+
drawGridLines(ctx, visible, spacing, options.size ?? DEFAULT_LINE_WIDTH, color, opacity);
|
|
648
|
+
break;
|
|
649
|
+
case "dots":
|
|
650
|
+
drawDotPattern(ctx, visible, spacing, options.size ?? DEFAULT_DOT_RADIUS, color, opacity);
|
|
651
|
+
break;
|
|
652
|
+
}
|
|
653
|
+
ctx.restore();
|
|
654
|
+
}
|
|
655
|
+
|
|
551
656
|
// src/input/inputManager.ts
|
|
552
657
|
var InputManager = class {
|
|
553
658
|
_current = { x: 0, y: 0 };
|
|
@@ -1711,7 +1816,7 @@ var Editor = class {
|
|
|
1711
1816
|
historyBatchChanged = false;
|
|
1712
1817
|
// Creates a new editor instance with the given options (with defaults if not provided)
|
|
1713
1818
|
constructor(opts = {}) {
|
|
1714
|
-
this.options = { dragDistanceSquared: opts.dragDistanceSquared ?? DRAG_DISTANCE_SQUARED };
|
|
1819
|
+
this.options = { dragDistanceSquared: opts.dragDistanceSquared ?? DRAG_DISTANCE_SQUARED, zoomRange: opts.zoomRange };
|
|
1715
1820
|
this.lastDocumentSnapshot = this.getDocumentSnapshot();
|
|
1716
1821
|
this.store.listen(() => {
|
|
1717
1822
|
this.captureDocumentHistory();
|
|
@@ -1825,7 +1930,7 @@ var Editor = class {
|
|
|
1825
1930
|
this.viewport = {
|
|
1826
1931
|
x: partial.x ?? this.viewport.x,
|
|
1827
1932
|
y: partial.y ?? this.viewport.y,
|
|
1828
|
-
zoom:
|
|
1933
|
+
zoom: clampZoom(rawZoom, this.options.zoomRange)
|
|
1829
1934
|
};
|
|
1830
1935
|
this.emitChange();
|
|
1831
1936
|
}
|
|
@@ -1836,7 +1941,7 @@ var Editor = class {
|
|
|
1836
1941
|
});
|
|
1837
1942
|
}
|
|
1838
1943
|
zoomAt(factor, screenX, screenY) {
|
|
1839
|
-
this.viewport = zoomViewport(this.viewport, factor, screenX, screenY);
|
|
1944
|
+
this.viewport = zoomViewport(this.viewport, factor, screenX, screenY, this.options.zoomRange);
|
|
1840
1945
|
this.emitChange();
|
|
1841
1946
|
}
|
|
1842
1947
|
deleteShapes(ids) {
|
|
@@ -2260,6 +2365,7 @@ exports.CanvasRenderer = CanvasRenderer;
|
|
|
2260
2365
|
exports.CircleDrawingState = CircleDrawingState;
|
|
2261
2366
|
exports.CircleIdleState = CircleIdleState;
|
|
2262
2367
|
exports.DEFAULT_COLORS = DEFAULT_COLORS;
|
|
2368
|
+
exports.DEFAULT_ZOOM_RANGE = DEFAULT_ZOOM_RANGE;
|
|
2263
2369
|
exports.DRAG_DISTANCE_SQUARED = DRAG_DISTANCE_SQUARED;
|
|
2264
2370
|
exports.DocumentStore = DocumentStore;
|
|
2265
2371
|
exports.ERASER_MARGIN = ERASER_MARGIN;
|
|
@@ -2288,6 +2394,7 @@ exports.boundsIntersect = boundsIntersect;
|
|
|
2288
2394
|
exports.boundsOf = boundsOf;
|
|
2289
2395
|
exports.buildStartPositions = buildStartPositions;
|
|
2290
2396
|
exports.buildTransformSnapshots = buildTransformSnapshots;
|
|
2397
|
+
exports.clampZoom = clampZoom;
|
|
2291
2398
|
exports.closestOnSegment = closestOnSegment;
|
|
2292
2399
|
exports.createViewport = createViewport;
|
|
2293
2400
|
exports.decodeFirstPoint = decodeFirstPoint;
|
|
@@ -2310,6 +2417,7 @@ exports.pageToScreen = pageToScreen;
|
|
|
2310
2417
|
exports.panViewport = panViewport;
|
|
2311
2418
|
exports.pointHitsShape = pointHitsShape;
|
|
2312
2419
|
exports.recordsToDocumentSnapshot = recordsToDocumentSnapshot;
|
|
2420
|
+
exports.renderCanvasBackground = renderCanvasBackground;
|
|
2313
2421
|
exports.resolveThemeColor = resolveThemeColor;
|
|
2314
2422
|
exports.rotatePoint = rotatePoint;
|
|
2315
2423
|
exports.screenToPage = screenToPage;
|