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