@tsdraw/core 0.6.2 → 0.8.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 +338 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -2
- package/dist/index.d.ts +87 -2
- package/dist/index.js +334 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -223,25 +223,34 @@ var StateNode = class {
|
|
|
223
223
|
|
|
224
224
|
// src/canvas/viewport.ts
|
|
225
225
|
function createViewport() {
|
|
226
|
-
return { x: 0, y: 0, zoom: 1 };
|
|
226
|
+
return { x: 0, y: 0, zoom: 1, rotation: 0 };
|
|
227
227
|
}
|
|
228
228
|
function screenToPage(viewport, screenX, screenY) {
|
|
229
|
+
const tx = screenX - viewport.x;
|
|
230
|
+
const ty = screenY - viewport.y;
|
|
231
|
+
const cos = Math.cos(viewport.rotation);
|
|
232
|
+
const sin = Math.sin(viewport.rotation);
|
|
229
233
|
return {
|
|
230
|
-
x: (
|
|
231
|
-
y: (
|
|
234
|
+
x: (tx * cos + ty * sin) / viewport.zoom,
|
|
235
|
+
y: (-tx * sin + ty * cos) / viewport.zoom
|
|
232
236
|
};
|
|
233
237
|
}
|
|
234
238
|
function pageToScreen(viewport, pageX, pageY) {
|
|
239
|
+
const scaledX = pageX * viewport.zoom;
|
|
240
|
+
const scaledY = pageY * viewport.zoom;
|
|
241
|
+
const cos = Math.cos(viewport.rotation);
|
|
242
|
+
const sin = Math.sin(viewport.rotation);
|
|
235
243
|
return {
|
|
236
|
-
x:
|
|
237
|
-
y:
|
|
244
|
+
x: scaledX * cos - scaledY * sin + viewport.x,
|
|
245
|
+
y: scaledX * sin + scaledY * cos + viewport.y
|
|
238
246
|
};
|
|
239
247
|
}
|
|
240
248
|
function setViewport(viewport, updater) {
|
|
241
249
|
return {
|
|
242
250
|
x: updater.x ?? viewport.x,
|
|
243
251
|
y: updater.y ?? viewport.y,
|
|
244
|
-
zoom: updater.zoom ?? viewport.zoom
|
|
252
|
+
zoom: updater.zoom ?? viewport.zoom,
|
|
253
|
+
rotation: updater.rotation ?? viewport.rotation
|
|
245
254
|
};
|
|
246
255
|
}
|
|
247
256
|
function panViewport(viewport, dx, dy) {
|
|
@@ -253,9 +262,23 @@ function zoomViewport(viewport, factor, centerX, centerY) {
|
|
|
253
262
|
return { ...viewport, zoom };
|
|
254
263
|
}
|
|
255
264
|
const pageBefore = screenToPage(viewport, centerX, centerY);
|
|
256
|
-
const
|
|
257
|
-
const
|
|
258
|
-
|
|
265
|
+
const cos = Math.cos(viewport.rotation);
|
|
266
|
+
const sin = Math.sin(viewport.rotation);
|
|
267
|
+
const x = centerX - (pageBefore.x * zoom * cos - pageBefore.y * zoom * sin);
|
|
268
|
+
const y = centerY - (pageBefore.x * zoom * sin + pageBefore.y * zoom * cos);
|
|
269
|
+
return { x, y, zoom, rotation: viewport.rotation };
|
|
270
|
+
}
|
|
271
|
+
function rotateViewport(viewport, delta, centerX, centerY) {
|
|
272
|
+
const rotation = viewport.rotation + delta;
|
|
273
|
+
if (centerX == null || centerY == null) {
|
|
274
|
+
return { ...viewport, rotation };
|
|
275
|
+
}
|
|
276
|
+
const pageBefore = screenToPage(viewport, centerX, centerY);
|
|
277
|
+
const cos = Math.cos(rotation);
|
|
278
|
+
const sin = Math.sin(rotation);
|
|
279
|
+
const x = centerX - (pageBefore.x * viewport.zoom * cos - pageBefore.y * viewport.zoom * sin);
|
|
280
|
+
const y = centerY - (pageBefore.x * viewport.zoom * sin + pageBefore.y * viewport.zoom * cos);
|
|
281
|
+
return { x, y, zoom: viewport.zoom, rotation };
|
|
259
282
|
}
|
|
260
283
|
|
|
261
284
|
// src/utils/colors.ts
|
|
@@ -288,6 +311,7 @@ var CanvasRenderer = class {
|
|
|
288
311
|
render(ctx, viewport, shapes) {
|
|
289
312
|
ctx.save();
|
|
290
313
|
ctx.translate(viewport.x, viewport.y);
|
|
314
|
+
ctx.rotate(viewport.rotation);
|
|
291
315
|
ctx.scale(viewport.zoom, viewport.zoom);
|
|
292
316
|
for (const shape of shapes) {
|
|
293
317
|
if (shape.type === "draw") {
|
|
@@ -296,11 +320,16 @@ var CanvasRenderer = class {
|
|
|
296
320
|
}
|
|
297
321
|
ctx.restore();
|
|
298
322
|
}
|
|
323
|
+
// Paints a single stroke
|
|
299
324
|
paintStroke(ctx, shape) {
|
|
300
325
|
const width = (STROKE_WIDTHS[shape.props.size] ?? 3.5) * shape.props.scale;
|
|
301
326
|
const samples = flattenSegments(shape);
|
|
302
327
|
if (samples.length === 0) return;
|
|
303
328
|
const color = resolveThemeColor(shape.props.color, this.theme);
|
|
329
|
+
const fillStyle = shape.props.fill ?? "none";
|
|
330
|
+
if (shape.props.isClosed && fillStyle !== "none") {
|
|
331
|
+
this.paintClosedShapeFill(ctx, samples, color, fillStyle);
|
|
332
|
+
}
|
|
304
333
|
if (shape.props.dash !== "draw") {
|
|
305
334
|
this.paintDashedStroke(ctx, samples, width, color, shape.props.dash);
|
|
306
335
|
return;
|
|
@@ -347,6 +376,30 @@ var CanvasRenderer = class {
|
|
|
347
376
|
ctx.stroke();
|
|
348
377
|
ctx.restore();
|
|
349
378
|
}
|
|
379
|
+
// Closed shapes are shapes where their start and end point are the same
|
|
380
|
+
paintClosedShapeFill(ctx, samples, color, fillStyle) {
|
|
381
|
+
if (samples.length < 3) return;
|
|
382
|
+
ctx.save();
|
|
383
|
+
ctx.beginPath();
|
|
384
|
+
ctx.moveTo(samples[0].x, samples[0].y);
|
|
385
|
+
for (let i = 1; i < samples.length; i++) {
|
|
386
|
+
const sample = samples[i];
|
|
387
|
+
ctx.lineTo(sample.x, sample.y);
|
|
388
|
+
}
|
|
389
|
+
ctx.closePath();
|
|
390
|
+
if (fillStyle === "solid") {
|
|
391
|
+
ctx.fillStyle = color;
|
|
392
|
+
ctx.globalAlpha = 0.55;
|
|
393
|
+
} else if (fillStyle === "none") {
|
|
394
|
+
ctx.fillStyle = this.theme === "dark" ? "#0f0f0f" : "#fafafa";
|
|
395
|
+
ctx.globalAlpha = 1;
|
|
396
|
+
} else {
|
|
397
|
+
ctx.fillStyle = color;
|
|
398
|
+
ctx.globalAlpha = 0.28;
|
|
399
|
+
}
|
|
400
|
+
ctx.fill();
|
|
401
|
+
ctx.restore();
|
|
402
|
+
}
|
|
350
403
|
};
|
|
351
404
|
var PRESSURE_FLOOR = 0.025;
|
|
352
405
|
var STYLUS_CURVE = (t) => t * 0.65 + Math.sin(t * Math.PI / 2) * 0.35;
|
|
@@ -360,7 +413,7 @@ function remap(value, inRange, outRange, clamp = false) {
|
|
|
360
413
|
return outLo + (outHi - outLo) * clamped;
|
|
361
414
|
}
|
|
362
415
|
function strokeConfig(shape, width) {
|
|
363
|
-
const done = shape.props.isComplete;
|
|
416
|
+
const done = shape.props.isComplete || shape.props.isClosed === true;
|
|
364
417
|
if (shape.props.isPen) {
|
|
365
418
|
return {
|
|
366
419
|
size: 1 + width * 1.2,
|
|
@@ -419,9 +472,6 @@ function flattenSegments(shape) {
|
|
|
419
472
|
}
|
|
420
473
|
out.push(D);
|
|
421
474
|
}
|
|
422
|
-
if (out.length > 0 && !shape.props.isPen) {
|
|
423
|
-
for (const p of out) p.pressure = 0.5;
|
|
424
|
-
}
|
|
425
475
|
return out;
|
|
426
476
|
}
|
|
427
477
|
function getLineDash(dash, width) {
|
|
@@ -752,8 +802,8 @@ var PenDrawingState = class extends StateNode {
|
|
|
752
802
|
const penActive = inputs.getIsPen();
|
|
753
803
|
const z = this._startInfo?.point?.z ?? 0.5;
|
|
754
804
|
this._isPenDevice = penActive;
|
|
755
|
-
this._hasPressure = penActive
|
|
756
|
-
const pressure = this._hasPressure ? toFixed(z
|
|
805
|
+
this._hasPressure = penActive || z !== 0.5;
|
|
806
|
+
const pressure = this._hasPressure ? toFixed(z) : 0.5;
|
|
757
807
|
this._phase = inputs.getShiftKey() ? "straight" : "free";
|
|
758
808
|
this._extending = false;
|
|
759
809
|
this._lastSample = { ...origin };
|
|
@@ -848,8 +898,15 @@ var PenDrawingState = class extends StateNode {
|
|
|
848
898
|
const { id, props: { size, scale } } = target;
|
|
849
899
|
const { segments } = shape.props;
|
|
850
900
|
const curPt = inputs.getCurrentPagePoint();
|
|
901
|
+
if (!this._hasPressure) {
|
|
902
|
+
const liveZ = curPt.z ?? 0.5;
|
|
903
|
+
if (liveZ !== 0.5 || inputs.getIsPen()) {
|
|
904
|
+
this._hasPressure = true;
|
|
905
|
+
this.editor.updateShapes([{ id, type: "draw", props: { isPen: true } }]);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
851
908
|
const local = this.editor.getPointInShapeSpace(shape, curPt);
|
|
852
|
-
const pressure = this._hasPressure ? toFixed(
|
|
909
|
+
const pressure = this._hasPressure ? toFixed(curPt.z ?? 0.5) : 0.5;
|
|
853
910
|
const pt = { x: toFixed(local.x), y: toFixed(local.y), z: pressure };
|
|
854
911
|
switch (this._phase) {
|
|
855
912
|
case "starting_straight": {
|
|
@@ -995,7 +1052,7 @@ var PenDrawingState = class extends StateNode {
|
|
|
995
1052
|
const firstPt = {
|
|
996
1053
|
x: 0,
|
|
997
1054
|
y: 0,
|
|
998
|
-
z: this._hasPressure ? toFixed(
|
|
1055
|
+
z: this._hasPressure ? toFixed(curPage.z ?? 0.5) : 0.5
|
|
999
1056
|
};
|
|
1000
1057
|
this._activePts = [firstPt];
|
|
1001
1058
|
this.editor.createShape({
|
|
@@ -1033,6 +1090,236 @@ var PenDrawingState = class extends StateNode {
|
|
|
1033
1090
|
}
|
|
1034
1091
|
};
|
|
1035
1092
|
|
|
1093
|
+
// src/tools/square/states/SquareIdleState.ts
|
|
1094
|
+
var SquareIdleState = class extends StateNode {
|
|
1095
|
+
static id = "square_idle";
|
|
1096
|
+
onPointerDown(info) {
|
|
1097
|
+
this.ctx.transition("square_drawing", info);
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1101
|
+
// src/tools/geometric/states/GeometricDrawingState.ts
|
|
1102
|
+
var GeometricDrawingState = class extends StateNode {
|
|
1103
|
+
currentShapeId = null;
|
|
1104
|
+
startedAt = { point: { x: 0, y: 0, z: 0.5 } };
|
|
1105
|
+
onEnter(info) {
|
|
1106
|
+
this.startedAt = info ?? { point: { x: 0, y: 0, z: 0.5 } };
|
|
1107
|
+
const originPoint = this.editor.input.getOriginPagePoint();
|
|
1108
|
+
const drawStyle = this.editor.getCurrentDrawStyle();
|
|
1109
|
+
const nextShapeId = this.editor.createShapeId();
|
|
1110
|
+
const config = this.getConfig();
|
|
1111
|
+
this.editor.createShape({
|
|
1112
|
+
id: nextShapeId,
|
|
1113
|
+
type: "draw",
|
|
1114
|
+
x: originPoint.x,
|
|
1115
|
+
y: originPoint.y,
|
|
1116
|
+
props: {
|
|
1117
|
+
color: drawStyle.color,
|
|
1118
|
+
dash: drawStyle.dash,
|
|
1119
|
+
fill: drawStyle.fill,
|
|
1120
|
+
size: drawStyle.size,
|
|
1121
|
+
scale: 1,
|
|
1122
|
+
isPen: false,
|
|
1123
|
+
isComplete: false,
|
|
1124
|
+
isClosed: true,
|
|
1125
|
+
segments: config.buildSegments(1, 1)
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
this.currentShapeId = nextShapeId;
|
|
1129
|
+
}
|
|
1130
|
+
onPointerMove() {
|
|
1131
|
+
const activeShape = this.getActiveShape();
|
|
1132
|
+
if (!activeShape) return;
|
|
1133
|
+
const config = this.getConfig();
|
|
1134
|
+
const originPoint = this.editor.input.getOriginPagePoint();
|
|
1135
|
+
const cursorPoint = this.editor.input.getCurrentPagePoint();
|
|
1136
|
+
const shapeBounds = this.editor.input.getShiftKey() ? config.buildConstrainedBounds(originPoint.x, originPoint.y, cursorPoint.x, cursorPoint.y) : config.buildUnconstrainedBounds(originPoint.x, originPoint.y, cursorPoint.x, cursorPoint.y);
|
|
1137
|
+
this.editor.store.updateShape(activeShape.id, {
|
|
1138
|
+
x: shapeBounds.x,
|
|
1139
|
+
y: shapeBounds.y,
|
|
1140
|
+
props: {
|
|
1141
|
+
...activeShape.props,
|
|
1142
|
+
segments: config.buildSegments(shapeBounds.width, shapeBounds.height),
|
|
1143
|
+
isClosed: true
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
onPointerUp() {
|
|
1148
|
+
this.completeShape();
|
|
1149
|
+
}
|
|
1150
|
+
onCancel() {
|
|
1151
|
+
this.removeCurrentShape();
|
|
1152
|
+
this.ctx.transition(this.getConfig().idleStateId, this.startedAt);
|
|
1153
|
+
}
|
|
1154
|
+
onInterrupt() {
|
|
1155
|
+
this.completeShape();
|
|
1156
|
+
}
|
|
1157
|
+
onKeyDown() {
|
|
1158
|
+
this.onPointerMove();
|
|
1159
|
+
}
|
|
1160
|
+
onKeyUp() {
|
|
1161
|
+
this.onPointerMove();
|
|
1162
|
+
}
|
|
1163
|
+
completeShape() {
|
|
1164
|
+
const activeShape = this.getActiveShape();
|
|
1165
|
+
const config = this.getConfig();
|
|
1166
|
+
if (!activeShape) {
|
|
1167
|
+
this.ctx.transition(config.idleStateId, this.startedAt);
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const originPoint = this.editor.input.getOriginPagePoint();
|
|
1171
|
+
const cursorPoint = this.editor.input.getCurrentPagePoint();
|
|
1172
|
+
const finalizedBounds = this.editor.input.getIsDragging() ? this.editor.input.getShiftKey() ? config.buildConstrainedBounds(originPoint.x, originPoint.y, cursorPoint.x, cursorPoint.y) : config.buildUnconstrainedBounds(originPoint.x, originPoint.y, cursorPoint.x, cursorPoint.y) : config.buildDefaultBounds(originPoint.x, originPoint.y);
|
|
1173
|
+
this.editor.store.updateShape(activeShape.id, {
|
|
1174
|
+
x: finalizedBounds.x,
|
|
1175
|
+
y: finalizedBounds.y,
|
|
1176
|
+
props: {
|
|
1177
|
+
...activeShape.props,
|
|
1178
|
+
fill: this.editor.getCurrentDrawStyle().fill,
|
|
1179
|
+
isComplete: true,
|
|
1180
|
+
isClosed: true,
|
|
1181
|
+
segments: config.buildSegments(finalizedBounds.width, finalizedBounds.height)
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
this.currentShapeId = null;
|
|
1185
|
+
this.ctx.transition(config.idleStateId);
|
|
1186
|
+
}
|
|
1187
|
+
removeCurrentShape() {
|
|
1188
|
+
if (!this.currentShapeId) return;
|
|
1189
|
+
this.editor.store.deleteShapes([this.currentShapeId]);
|
|
1190
|
+
this.currentShapeId = null;
|
|
1191
|
+
}
|
|
1192
|
+
getActiveShape() {
|
|
1193
|
+
if (!this.currentShapeId) return null;
|
|
1194
|
+
const shape = this.editor.getShape(this.currentShapeId);
|
|
1195
|
+
if (!shape || shape.type !== "draw") return null;
|
|
1196
|
+
return shape;
|
|
1197
|
+
}
|
|
1198
|
+
};
|
|
1199
|
+
|
|
1200
|
+
// src/tools/geometric/geometricShapeHelpers.ts
|
|
1201
|
+
var MIN_SIDE_LENGTH = 1;
|
|
1202
|
+
var DEFAULT_RECTANGLE_WIDTH = 180;
|
|
1203
|
+
var DEFAULT_RECTANGLE_HEIGHT = 120;
|
|
1204
|
+
var DEFAULT_ELLIPSE_WIDTH = 180;
|
|
1205
|
+
var DEFAULT_ELLIPSE_HEIGHT = 120;
|
|
1206
|
+
function toSizedBounds(anchorX, anchorY, cursorX, cursorY, forceEqualSides) {
|
|
1207
|
+
const rawDeltaX = cursorX - anchorX;
|
|
1208
|
+
const rawDeltaY = cursorY - anchorY;
|
|
1209
|
+
const sideLength = Math.max(Math.abs(rawDeltaX), Math.abs(rawDeltaY), MIN_SIDE_LENGTH);
|
|
1210
|
+
if (forceEqualSides) {
|
|
1211
|
+
const nextDeltaX = rawDeltaX < 0 ? -sideLength : sideLength;
|
|
1212
|
+
const nextDeltaY = rawDeltaY < 0 ? -sideLength : sideLength;
|
|
1213
|
+
return normalizeBounds(anchorX, anchorY, anchorX + nextDeltaX, anchorY + nextDeltaY);
|
|
1214
|
+
}
|
|
1215
|
+
return normalizeBounds(anchorX, anchorY, cursorX, cursorY);
|
|
1216
|
+
}
|
|
1217
|
+
function normalizeBounds(startX, startY, endX, endY) {
|
|
1218
|
+
const x = Math.min(startX, endX);
|
|
1219
|
+
const y = Math.min(startY, endY);
|
|
1220
|
+
const width = Math.max(Math.abs(endX - startX), MIN_SIDE_LENGTH);
|
|
1221
|
+
const height = Math.max(Math.abs(endY - startY), MIN_SIDE_LENGTH);
|
|
1222
|
+
return { x, y, width, height };
|
|
1223
|
+
}
|
|
1224
|
+
function buildSquareBounds(anchorX, anchorY, cursorX, cursorY) {
|
|
1225
|
+
return toSizedBounds(anchorX, anchorY, cursorX, cursorY, true);
|
|
1226
|
+
}
|
|
1227
|
+
function buildRectangleBounds(anchorX, anchorY, cursorX, cursorY) {
|
|
1228
|
+
return toSizedBounds(anchorX, anchorY, cursorX, cursorY, false);
|
|
1229
|
+
}
|
|
1230
|
+
function buildDefaultCenteredRectangleBounds(centerX, centerY) {
|
|
1231
|
+
const halfWidth = DEFAULT_RECTANGLE_WIDTH / 2;
|
|
1232
|
+
const halfHeight = DEFAULT_RECTANGLE_HEIGHT / 2;
|
|
1233
|
+
return {
|
|
1234
|
+
x: centerX - halfWidth,
|
|
1235
|
+
y: centerY - halfHeight,
|
|
1236
|
+
width: DEFAULT_RECTANGLE_WIDTH,
|
|
1237
|
+
height: DEFAULT_RECTANGLE_HEIGHT
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
function buildRectangleSegments(width, height) {
|
|
1241
|
+
const topLeft = { x: 0, y: 0, z: 0.5 };
|
|
1242
|
+
const topRight = { x: width, y: 0, z: 0.5 };
|
|
1243
|
+
const bottomRight = { x: width, y: height, z: 0.5 };
|
|
1244
|
+
const bottomLeft = { x: 0, y: height, z: 0.5 };
|
|
1245
|
+
return [
|
|
1246
|
+
{ type: "straight", path: encodePoints([topLeft, topRight]) },
|
|
1247
|
+
{ type: "straight", path: encodePoints([topRight, bottomRight]) },
|
|
1248
|
+
{ type: "straight", path: encodePoints([bottomRight, bottomLeft]) },
|
|
1249
|
+
{ type: "straight", path: encodePoints([bottomLeft, topLeft]) }
|
|
1250
|
+
];
|
|
1251
|
+
}
|
|
1252
|
+
function buildCircleBounds(anchorX, anchorY, cursorX, cursorY) {
|
|
1253
|
+
return toSizedBounds(anchorX, anchorY, cursorX, cursorY, true);
|
|
1254
|
+
}
|
|
1255
|
+
function buildEllipseBounds(anchorX, anchorY, cursorX, cursorY) {
|
|
1256
|
+
return toSizedBounds(anchorX, anchorY, cursorX, cursorY, false);
|
|
1257
|
+
}
|
|
1258
|
+
function buildDefaultCenteredEllipseBounds(centerX, centerY) {
|
|
1259
|
+
const halfWidth = DEFAULT_ELLIPSE_WIDTH / 2;
|
|
1260
|
+
const halfHeight = DEFAULT_ELLIPSE_HEIGHT / 2;
|
|
1261
|
+
return {
|
|
1262
|
+
x: centerX - halfWidth,
|
|
1263
|
+
y: centerY - halfHeight,
|
|
1264
|
+
width: DEFAULT_ELLIPSE_WIDTH,
|
|
1265
|
+
height: DEFAULT_ELLIPSE_HEIGHT
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
function buildEllipseSegments(width, height) {
|
|
1269
|
+
const centerX = width / 2;
|
|
1270
|
+
const centerY = height / 2;
|
|
1271
|
+
const radiusX = width / 2;
|
|
1272
|
+
const radiusY = height / 2;
|
|
1273
|
+
const sampleCount = 64;
|
|
1274
|
+
const sampledPoints = [];
|
|
1275
|
+
for (let sampleIndex = 0; sampleIndex <= sampleCount; sampleIndex += 1) {
|
|
1276
|
+
const progress = sampleIndex / sampleCount;
|
|
1277
|
+
const angle = progress * Math.PI * 2;
|
|
1278
|
+
sampledPoints.push({
|
|
1279
|
+
x: centerX + Math.cos(angle) * radiusX,
|
|
1280
|
+
y: centerY + Math.sin(angle) * radiusY,
|
|
1281
|
+
z: 0.5
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
return [{ type: "free", path: encodePoints(sampledPoints) }];
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// src/tools/square/states/SquareDrawingState.ts
|
|
1288
|
+
var SquareDrawingState = class extends GeometricDrawingState {
|
|
1289
|
+
static id = "square_drawing";
|
|
1290
|
+
getConfig() {
|
|
1291
|
+
return {
|
|
1292
|
+
idleStateId: "square_idle",
|
|
1293
|
+
buildConstrainedBounds: buildSquareBounds,
|
|
1294
|
+
buildUnconstrainedBounds: buildRectangleBounds,
|
|
1295
|
+
buildDefaultBounds: buildDefaultCenteredRectangleBounds,
|
|
1296
|
+
buildSegments: buildRectangleSegments
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1301
|
+
// src/tools/circle/states/CircleIdleState.ts
|
|
1302
|
+
var CircleIdleState = class extends StateNode {
|
|
1303
|
+
static id = "circle_idle";
|
|
1304
|
+
onPointerDown(info) {
|
|
1305
|
+
this.ctx.transition("circle_drawing", info);
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
|
|
1309
|
+
// src/tools/circle/states/CircleDrawingState.ts
|
|
1310
|
+
var CircleDrawingState = class extends GeometricDrawingState {
|
|
1311
|
+
static id = "circle_drawing";
|
|
1312
|
+
getConfig() {
|
|
1313
|
+
return {
|
|
1314
|
+
idleStateId: "circle_idle",
|
|
1315
|
+
buildConstrainedBounds: buildCircleBounds,
|
|
1316
|
+
buildUnconstrainedBounds: buildEllipseBounds,
|
|
1317
|
+
buildDefaultBounds: buildDefaultCenteredEllipseBounds,
|
|
1318
|
+
buildSegments: buildEllipseSegments
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
|
|
1036
1323
|
// src/tools/eraser/states/EraserIdleState.ts
|
|
1037
1324
|
var EraserIdleState = class extends StateNode {
|
|
1038
1325
|
static id = "eraser_idle";
|
|
@@ -1346,6 +1633,7 @@ var Editor = class {
|
|
|
1346
1633
|
drawStyle = {
|
|
1347
1634
|
color: "black",
|
|
1348
1635
|
dash: "draw",
|
|
1636
|
+
fill: "none",
|
|
1349
1637
|
size: "m"
|
|
1350
1638
|
};
|
|
1351
1639
|
toolStateContext;
|
|
@@ -1405,6 +1693,8 @@ var Editor = class {
|
|
|
1405
1693
|
getDefaultToolDefinitions() {
|
|
1406
1694
|
return [
|
|
1407
1695
|
{ id: "pen", initialStateId: PenIdleState.id, stateConstructors: [PenIdleState, PenDrawingState] },
|
|
1696
|
+
{ id: "square", initialStateId: SquareIdleState.id, stateConstructors: [SquareIdleState, SquareDrawingState] },
|
|
1697
|
+
{ id: "circle", initialStateId: CircleIdleState.id, stateConstructors: [CircleIdleState, CircleDrawingState] },
|
|
1408
1698
|
{ id: "eraser", initialStateId: EraserIdleState.id, stateConstructors: [EraserIdleState, EraserPointingState, EraserErasingState] },
|
|
1409
1699
|
{ id: "select", initialStateId: SelectIdleState.id, stateConstructors: [SelectIdleState] },
|
|
1410
1700
|
{ id: "hand", initialStateId: HandIdleState.id, stateConstructors: [HandIdleState, HandDraggingState] }
|
|
@@ -1472,7 +1762,8 @@ var Editor = class {
|
|
|
1472
1762
|
this.viewport = {
|
|
1473
1763
|
x: partial.x ?? this.viewport.x,
|
|
1474
1764
|
y: partial.y ?? this.viewport.y,
|
|
1475
|
-
zoom: Math.max(0.1, Math.min(4, rawZoom))
|
|
1765
|
+
zoom: Math.max(0.1, Math.min(4, rawZoom)),
|
|
1766
|
+
rotation: partial.rotation ?? this.viewport.rotation
|
|
1476
1767
|
};
|
|
1477
1768
|
this.emitChange();
|
|
1478
1769
|
}
|
|
@@ -1482,6 +1773,18 @@ var Editor = class {
|
|
|
1482
1773
|
y: this.viewport.y + dy
|
|
1483
1774
|
});
|
|
1484
1775
|
}
|
|
1776
|
+
zoomAt(factor, screenX, screenY) {
|
|
1777
|
+
this.viewport = zoomViewport(this.viewport, factor, screenX, screenY);
|
|
1778
|
+
this.emitChange();
|
|
1779
|
+
}
|
|
1780
|
+
rotateAt(delta, screenX, screenY) {
|
|
1781
|
+
this.viewport = rotateViewport(this.viewport, delta, screenX, screenY);
|
|
1782
|
+
this.emitChange();
|
|
1783
|
+
}
|
|
1784
|
+
deleteShapes(ids) {
|
|
1785
|
+
if (ids.length === 0) return;
|
|
1786
|
+
this.store.deleteShapes(ids);
|
|
1787
|
+
}
|
|
1485
1788
|
getDocumentSnapshot() {
|
|
1486
1789
|
return {
|
|
1487
1790
|
records: documentSnapshotToRecords(this.store.getSnapshot())
|
|
@@ -1500,7 +1803,8 @@ var Editor = class {
|
|
|
1500
1803
|
viewport: {
|
|
1501
1804
|
x: this.viewport.x,
|
|
1502
1805
|
y: this.viewport.y,
|
|
1503
|
-
zoom: this.viewport.zoom
|
|
1806
|
+
zoom: this.viewport.zoom,
|
|
1807
|
+
rotation: this.viewport.rotation
|
|
1504
1808
|
},
|
|
1505
1809
|
currentToolId: this.getCurrentToolId(),
|
|
1506
1810
|
drawStyle: this.getCurrentDrawStyle(),
|
|
@@ -1508,8 +1812,16 @@ var Editor = class {
|
|
|
1508
1812
|
};
|
|
1509
1813
|
}
|
|
1510
1814
|
loadSessionStateSnapshot(snapshot) {
|
|
1511
|
-
this.setViewport(
|
|
1512
|
-
|
|
1815
|
+
this.setViewport({
|
|
1816
|
+
...snapshot.viewport,
|
|
1817
|
+
rotation: snapshot.viewport.rotation ?? 0
|
|
1818
|
+
});
|
|
1819
|
+
this.setCurrentDrawStyle({
|
|
1820
|
+
color: snapshot.drawStyle.color,
|
|
1821
|
+
dash: snapshot.drawStyle.dash,
|
|
1822
|
+
fill: snapshot.drawStyle.fill ?? "none",
|
|
1823
|
+
size: snapshot.drawStyle.size
|
|
1824
|
+
});
|
|
1513
1825
|
if (this.tools.hasTool(snapshot.currentToolId)) {
|
|
1514
1826
|
this.setCurrentTool(snapshot.currentToolId);
|
|
1515
1827
|
}
|
|
@@ -1890,6 +2202,6 @@ function applyResize(editor, handle, startBounds, startShapes, pointer, lockAspe
|
|
|
1890
2202
|
}
|
|
1891
2203
|
}
|
|
1892
2204
|
|
|
1893
|
-
export { CanvasRenderer, DEFAULT_COLORS, DRAG_DISTANCE_SQUARED, DocumentStore, ERASER_MARGIN, Editor, EraserErasingState, EraserIdleState, EraserPointingState, HandDraggingState, HandIdleState, InputManager, MAX_POINTS_PER_SHAPE, PenDrawingState, PenIdleState, STROKE_WIDTHS, SelectIdleState, StateNode, ToolManager, applyMove, applyResize, applyRotation, boundsContainPoint, boundsIntersect, boundsOf, buildStartPositions, buildTransformSnapshots, closestOnSegment, createViewport, decodeFirstPoint, decodeLastPoint, decodePathToPoints, decodePoints, distance, documentSnapshotToRecords, encodePoints, getSelectionBoundsPage, getShapeBounds2 as getShapeBounds, getShapesInBounds, getTopShapeAtPoint, isSelectTool, minDistanceToPolyline, normalizeSelectionBounds, padBounds, pageToScreen, panViewport, pointHitsShape, recordsToDocumentSnapshot, resolveThemeColor, rotatePoint, screenToPage, segmentHitsShape, segmentTouchesPolyline, setViewport, shapePagePoints, sqDistance, zoomViewport };
|
|
2205
|
+
export { CanvasRenderer, CircleDrawingState, CircleIdleState, DEFAULT_COLORS, DRAG_DISTANCE_SQUARED, DocumentStore, ERASER_MARGIN, Editor, EraserErasingState, EraserIdleState, EraserPointingState, HandDraggingState, HandIdleState, InputManager, MAX_POINTS_PER_SHAPE, PenDrawingState, PenIdleState, STROKE_WIDTHS, SelectIdleState, SquareDrawingState, SquareIdleState, StateNode, ToolManager, applyMove, applyResize, applyRotation, boundsContainPoint, boundsIntersect, boundsOf, buildStartPositions, buildTransformSnapshots, closestOnSegment, createViewport, decodeFirstPoint, decodeLastPoint, decodePathToPoints, decodePoints, distance, documentSnapshotToRecords, encodePoints, getSelectionBoundsPage, getShapeBounds2 as getShapeBounds, getShapesInBounds, getTopShapeAtPoint, isSelectTool, minDistanceToPolyline, normalizeSelectionBounds, padBounds, pageToScreen, panViewport, pointHitsShape, recordsToDocumentSnapshot, resolveThemeColor, rotatePoint, rotateViewport, screenToPage, segmentHitsShape, segmentTouchesPolyline, setViewport, shapePagePoints, sqDistance, zoomViewport };
|
|
1894
2206
|
//# sourceMappingURL=index.js.map
|
|
1895
2207
|
//# sourceMappingURL=index.js.map
|