@fieldnotes/core 0.47.0 → 0.48.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 +295 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +294 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -69,6 +69,7 @@ __export(index_exports, {
|
|
|
69
69
|
getHexCellsInCone: () => getHexCellsInCone,
|
|
70
70
|
getHexCellsInLine: () => getHexCellsInLine,
|
|
71
71
|
getHexCellsInRadius: () => getHexCellsInRadius,
|
|
72
|
+
getHexCellsInRectangle: () => getHexCellsInRectangle,
|
|
72
73
|
getHexCellsInSquare: () => getHexCellsInSquare,
|
|
73
74
|
getHexDistance: () => getHexDistance,
|
|
74
75
|
isNearBezier: () => isNearBezier,
|
|
@@ -983,6 +984,26 @@ function getTemplateBounds(el) {
|
|
|
983
984
|
const maxY = Math.max(y0, y1, y2, y3);
|
|
984
985
|
return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
|
|
985
986
|
}
|
|
987
|
+
case "rectangle": {
|
|
988
|
+
const halfW = (el.width ?? 0) / 2;
|
|
989
|
+
const cos = Math.cos(el.angle);
|
|
990
|
+
const sin = Math.sin(el.angle);
|
|
991
|
+
const perpX = -sin * halfW;
|
|
992
|
+
const perpY = cos * halfW;
|
|
993
|
+
const x0 = cx + perpX;
|
|
994
|
+
const y0 = cy + perpY;
|
|
995
|
+
const x1 = cx + r * cos + perpX;
|
|
996
|
+
const y1 = cy + r * sin + perpY;
|
|
997
|
+
const x2 = cx + r * cos - perpX;
|
|
998
|
+
const y2 = cy + r * sin - perpY;
|
|
999
|
+
const x3 = cx - perpX;
|
|
1000
|
+
const y3 = cy - perpY;
|
|
1001
|
+
const minX = Math.min(x0, x1, x2, x3);
|
|
1002
|
+
const minY = Math.min(y0, y1, y2, y3);
|
|
1003
|
+
const maxX = Math.max(x0, x1, x2, x3);
|
|
1004
|
+
const maxY = Math.max(y0, y1, y2, y3);
|
|
1005
|
+
return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
|
|
1006
|
+
}
|
|
986
1007
|
}
|
|
987
1008
|
}
|
|
988
1009
|
function transferStrokeBounds(prev, next) {
|
|
@@ -3286,6 +3307,46 @@ function getHexCellsInLine(center2, angle, radiusCells, cellSize, orientation) {
|
|
|
3286
3307
|
}
|
|
3287
3308
|
return cells;
|
|
3288
3309
|
}
|
|
3310
|
+
function getHexCellsInRectangle(center2, angle, lengthCells, widthCells, cellSize, orientation) {
|
|
3311
|
+
const nLen = Math.round(lengthCells);
|
|
3312
|
+
const wCells = Math.max(1, Math.round(widthCells));
|
|
3313
|
+
const off = pixelToOffset(center2.x, center2.y, cellSize, orientation);
|
|
3314
|
+
const cube = offsetToCube(off.col, off.row, orientation);
|
|
3315
|
+
const centerPixel = offsetToPixel(off.col, off.row, cellSize, orientation);
|
|
3316
|
+
if (nLen <= 0) return [centerPixel];
|
|
3317
|
+
const vertexOffset = orientation === "pointy" ? Math.PI / 6 : 0;
|
|
3318
|
+
const step = Math.PI / 3;
|
|
3319
|
+
const snappedAngle = Math.round((angle - vertexOffset) / step) * step + vertexOffset;
|
|
3320
|
+
const cos = Math.cos(snappedAngle);
|
|
3321
|
+
const sin = Math.sin(snappedAngle);
|
|
3322
|
+
const snapUnit = Math.sqrt(3) * cellSize;
|
|
3323
|
+
const lineLength = nLen * snapUnit;
|
|
3324
|
+
const halfWidth = wCells * snapUnit / 2 + 1e-6;
|
|
3325
|
+
const iterM = nLen + Math.ceil(wCells / 2) + 1;
|
|
3326
|
+
const cells = [];
|
|
3327
|
+
for (let dq = -iterM; dq <= iterM; dq++) {
|
|
3328
|
+
const rMin = Math.max(-iterM, -dq - iterM);
|
|
3329
|
+
const rMax = Math.min(iterM, -dq + iterM);
|
|
3330
|
+
for (let dr = rMin; dr <= rMax; dr++) {
|
|
3331
|
+
const absQ = cube.q + dq;
|
|
3332
|
+
const absR = cube.r + dr;
|
|
3333
|
+
const pixel = offsetToPixel(
|
|
3334
|
+
cubeToOffset(absQ, absR, orientation).col,
|
|
3335
|
+
cubeToOffset(absQ, absR, orientation).row,
|
|
3336
|
+
cellSize,
|
|
3337
|
+
orientation
|
|
3338
|
+
);
|
|
3339
|
+
const dx = pixel.x - centerPixel.x;
|
|
3340
|
+
const dy = pixel.y - centerPixel.y;
|
|
3341
|
+
const along = dx * cos + dy * sin;
|
|
3342
|
+
const perp = Math.abs(-dx * sin + dy * cos);
|
|
3343
|
+
if (along >= -snapUnit * 0.1 && along <= lineLength + snapUnit * 0.1 && perp <= halfWidth) {
|
|
3344
|
+
cells.push(pixel);
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
return cells;
|
|
3349
|
+
}
|
|
3289
3350
|
function getHexCellsInSquare(center2, radiusCells, cellSize, orientation) {
|
|
3290
3351
|
const n2 = Math.round(radiusCells);
|
|
3291
3352
|
const off = pixelToOffset(center2.x, center2.y, cellSize, orientation);
|
|
@@ -3327,7 +3388,7 @@ function drawHexPath(ctx, cx, cy, cellSize, orientation) {
|
|
|
3327
3388
|
// src/elements/renderers/template-measure.ts
|
|
3328
3389
|
function renderTemplateFeetLabel(ctx, p) {
|
|
3329
3390
|
if (p.feet <= 0) return;
|
|
3330
|
-
const directional = p.templateShape === "cone" || p.templateShape === "line";
|
|
3391
|
+
const directional = p.templateShape === "cone" || p.templateShape === "line" || p.templateShape === "rectangle";
|
|
3331
3392
|
const dir = directional ? p.angle : 0;
|
|
3332
3393
|
const length = p.templateShape === "square" ? p.radius / 2 : p.radius;
|
|
3333
3394
|
const cos = Math.cos(dir);
|
|
@@ -3420,6 +3481,22 @@ function renderGeometricTemplate(ctx, template) {
|
|
|
3420
3481
|
ctx.stroke();
|
|
3421
3482
|
break;
|
|
3422
3483
|
}
|
|
3484
|
+
case "rectangle": {
|
|
3485
|
+
const halfW = (template.width ?? 0) / 2;
|
|
3486
|
+
const cos = Math.cos(template.angle);
|
|
3487
|
+
const sin = Math.sin(template.angle);
|
|
3488
|
+
const perpX = -sin * halfW;
|
|
3489
|
+
const perpY = cos * halfW;
|
|
3490
|
+
ctx.beginPath();
|
|
3491
|
+
ctx.moveTo(cx + perpX, cy + perpY);
|
|
3492
|
+
ctx.lineTo(cx + r * cos + perpX, cy + r * sin + perpY);
|
|
3493
|
+
ctx.lineTo(cx + r * cos - perpX, cy + r * sin - perpY);
|
|
3494
|
+
ctx.lineTo(cx - perpX, cy - perpY);
|
|
3495
|
+
ctx.closePath();
|
|
3496
|
+
ctx.fill();
|
|
3497
|
+
ctx.stroke();
|
|
3498
|
+
break;
|
|
3499
|
+
}
|
|
3423
3500
|
}
|
|
3424
3501
|
if (template.radiusFeet != null && template.radiusFeet > 0) {
|
|
3425
3502
|
renderTemplateFeetLabel(ctx, {
|
|
@@ -3451,6 +3528,18 @@ function renderHexTemplate(ctx, template, cellSize, orientation) {
|
|
|
3451
3528
|
case "square":
|
|
3452
3529
|
cells = getHexCellsInSquare(center2, radiusCells, cellSize, orientation);
|
|
3453
3530
|
break;
|
|
3531
|
+
case "rectangle": {
|
|
3532
|
+
const widthCells = (template.width ?? 0) / snapUnit;
|
|
3533
|
+
cells = getHexCellsInRectangle(
|
|
3534
|
+
center2,
|
|
3535
|
+
template.angle,
|
|
3536
|
+
radiusCells,
|
|
3537
|
+
widthCells,
|
|
3538
|
+
cellSize,
|
|
3539
|
+
orientation
|
|
3540
|
+
);
|
|
3541
|
+
break;
|
|
3542
|
+
}
|
|
3454
3543
|
}
|
|
3455
3544
|
ctx.save();
|
|
3456
3545
|
ctx.globalAlpha = template.opacity;
|
|
@@ -4027,7 +4116,8 @@ function createTemplate(input) {
|
|
|
4027
4116
|
opacity: input.opacity ?? 0.6,
|
|
4028
4117
|
feetPerCell: input.feetPerCell,
|
|
4029
4118
|
radiusFeet: input.radiusFeet,
|
|
4030
|
-
...input.renderStyle !== void 0 ? { renderStyle: input.renderStyle } : {}
|
|
4119
|
+
...input.renderStyle !== void 0 ? { renderStyle: input.renderStyle } : {},
|
|
4120
|
+
...input.width !== void 0 ? { width: input.width } : {}
|
|
4031
4121
|
};
|
|
4032
4122
|
}
|
|
4033
4123
|
|
|
@@ -5624,6 +5714,20 @@ function emitGeometricTemplate(t) {
|
|
|
5624
5714
|
].map(([px, py]) => `${n(px ?? 0)},${n(py ?? 0)}`).join(" ");
|
|
5625
5715
|
return `<polygon points="${pts}" ${attrs} />`;
|
|
5626
5716
|
}
|
|
5717
|
+
case "rectangle": {
|
|
5718
|
+
const halfW = (t.width ?? 0) / 2;
|
|
5719
|
+
const cos = Math.cos(t.angle);
|
|
5720
|
+
const sin = Math.sin(t.angle);
|
|
5721
|
+
const perpX = -sin * halfW;
|
|
5722
|
+
const perpY = cos * halfW;
|
|
5723
|
+
const pts = [
|
|
5724
|
+
[cx + perpX, cy + perpY],
|
|
5725
|
+
[cx + r * cos + perpX, cy + r * sin + perpY],
|
|
5726
|
+
[cx + r * cos - perpX, cy + r * sin - perpY],
|
|
5727
|
+
[cx - perpX, cy - perpY]
|
|
5728
|
+
].map(([px, py]) => `${n(px ?? 0)},${n(py ?? 0)}`).join(" ");
|
|
5729
|
+
return `<polygon points="${pts}" ${attrs} />`;
|
|
5730
|
+
}
|
|
5627
5731
|
}
|
|
5628
5732
|
}
|
|
5629
5733
|
function emitHexTemplate(t, grid) {
|
|
@@ -5646,6 +5750,18 @@ function emitHexTemplate(t, grid) {
|
|
|
5646
5750
|
case "square":
|
|
5647
5751
|
cells = getHexCellsInSquare(center2, radiusCells, cellSize, orientation);
|
|
5648
5752
|
break;
|
|
5753
|
+
case "rectangle": {
|
|
5754
|
+
const widthCells = (t.width ?? 0) / snapUnit;
|
|
5755
|
+
cells = getHexCellsInRectangle(
|
|
5756
|
+
center2,
|
|
5757
|
+
t.angle,
|
|
5758
|
+
radiusCells,
|
|
5759
|
+
widthCells,
|
|
5760
|
+
cellSize,
|
|
5761
|
+
orientation
|
|
5762
|
+
);
|
|
5763
|
+
break;
|
|
5764
|
+
}
|
|
5649
5765
|
}
|
|
5650
5766
|
let d = "";
|
|
5651
5767
|
for (const cell of cells) {
|
|
@@ -8336,7 +8452,8 @@ function getOverlayLayout(el, zoom) {
|
|
|
8336
8452
|
}
|
|
8337
8453
|
function templateAimKnob(el, zoom) {
|
|
8338
8454
|
if (el.type !== "template") return null;
|
|
8339
|
-
if (el.templateShape !== "cone" && el.templateShape !== "line"
|
|
8455
|
+
if (el.templateShape !== "cone" && el.templateShape !== "line" && el.templateShape !== "rectangle")
|
|
8456
|
+
return null;
|
|
8340
8457
|
const gap = ROTATE_HANDLE_OFFSET / zoom;
|
|
8341
8458
|
const dist = el.radius + gap;
|
|
8342
8459
|
const origin = el.position;
|
|
@@ -8481,22 +8598,51 @@ function renderSelectionBoxes(ctx, p) {
|
|
|
8481
8598
|
} else if (el.type === "template") {
|
|
8482
8599
|
ctx.setLineDash([]);
|
|
8483
8600
|
ctx.fillStyle = "#ffffff";
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8601
|
+
if (el.templateShape === "rectangle") {
|
|
8602
|
+
if (p.selectedIds.length === 1) {
|
|
8603
|
+
const cos = Math.cos(el.angle);
|
|
8604
|
+
const sin = Math.sin(el.angle);
|
|
8605
|
+
const halfW = (el.width ?? 0) / 2;
|
|
8606
|
+
const pts = [
|
|
8607
|
+
[el.position.x + el.radius * cos, el.position.y + el.radius * sin],
|
|
8608
|
+
[
|
|
8609
|
+
el.position.x + el.radius / 2 * cos + halfW * -sin,
|
|
8610
|
+
el.position.y + el.radius / 2 * sin + halfW * cos
|
|
8611
|
+
]
|
|
8612
|
+
];
|
|
8613
|
+
for (const [hx, hy] of pts) {
|
|
8614
|
+
ctx.fillRect(
|
|
8615
|
+
hx - handleWorldSize / 2,
|
|
8616
|
+
hy - handleWorldSize / 2,
|
|
8617
|
+
handleWorldSize,
|
|
8618
|
+
handleWorldSize
|
|
8619
|
+
);
|
|
8620
|
+
ctx.strokeRect(
|
|
8621
|
+
hx - handleWorldSize / 2,
|
|
8622
|
+
hy - handleWorldSize / 2,
|
|
8623
|
+
handleWorldSize,
|
|
8624
|
+
handleWorldSize
|
|
8625
|
+
);
|
|
8626
|
+
}
|
|
8627
|
+
}
|
|
8628
|
+
} else {
|
|
8629
|
+
const hx = bounds.x + bounds.w;
|
|
8630
|
+
const hy = bounds.y + bounds.h;
|
|
8631
|
+
ctx.fillRect(
|
|
8632
|
+
hx - handleWorldSize / 2,
|
|
8633
|
+
hy - handleWorldSize / 2,
|
|
8634
|
+
handleWorldSize,
|
|
8635
|
+
handleWorldSize
|
|
8636
|
+
);
|
|
8637
|
+
ctx.strokeRect(
|
|
8638
|
+
hx - handleWorldSize / 2,
|
|
8639
|
+
hy - handleWorldSize / 2,
|
|
8640
|
+
handleWorldSize,
|
|
8641
|
+
handleWorldSize
|
|
8642
|
+
);
|
|
8643
|
+
}
|
|
8498
8644
|
ctx.setLineDash([4 / zoom, 4 / zoom]);
|
|
8499
|
-
if (p.selectedIds.length === 1 && (el.templateShape === "cone" || el.templateShape === "line")) {
|
|
8645
|
+
if (p.selectedIds.length === 1 && (el.templateShape === "cone" || el.templateShape === "line" || el.templateShape === "rectangle")) {
|
|
8500
8646
|
const aim = templateAimKnob(el, zoom);
|
|
8501
8647
|
if (aim) {
|
|
8502
8648
|
ctx.beginPath();
|
|
@@ -8657,6 +8803,7 @@ function hitTestTemplateResizeHandle(world, ctx, selectedIds) {
|
|
|
8657
8803
|
for (const id of selectedIds) {
|
|
8658
8804
|
const el = ctx.store.getById(id);
|
|
8659
8805
|
if (!el || el.type !== "template") continue;
|
|
8806
|
+
if (el.templateShape === "rectangle") continue;
|
|
8660
8807
|
const bounds = getElementBounds(el);
|
|
8661
8808
|
if (!bounds) continue;
|
|
8662
8809
|
const hx = bounds.x + bounds.w;
|
|
@@ -8680,6 +8827,37 @@ function hitTestTemplateAimHandle(world, ctx, selectedIds) {
|
|
|
8680
8827
|
const dy = world.y - knob.knob.y;
|
|
8681
8828
|
return dx * dx + dy * dy <= r * r ? { elementId: id } : null;
|
|
8682
8829
|
}
|
|
8830
|
+
function hitTestRectangleLengthHandle(world, ctx, selectedIds) {
|
|
8831
|
+
if (selectedIds.length !== 1) return null;
|
|
8832
|
+
const id = selectedIds[0];
|
|
8833
|
+
if (!id) return null;
|
|
8834
|
+
const el = ctx.store.getById(id);
|
|
8835
|
+
if (!el || el.locked || el.type !== "template" || el.templateShape !== "rectangle") return null;
|
|
8836
|
+
const zoom = ctx.camera.zoom;
|
|
8837
|
+
const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING2) / zoom;
|
|
8838
|
+
const hx = el.position.x + el.radius * Math.cos(el.angle);
|
|
8839
|
+
const hy = el.position.y + el.radius * Math.sin(el.angle);
|
|
8840
|
+
const dx = world.x - hx;
|
|
8841
|
+
const dy = world.y - hy;
|
|
8842
|
+
return dx * dx + dy * dy <= r * r ? { elementId: id } : null;
|
|
8843
|
+
}
|
|
8844
|
+
function hitTestRectangleWidthHandle(world, ctx, selectedIds) {
|
|
8845
|
+
if (selectedIds.length !== 1) return null;
|
|
8846
|
+
const id = selectedIds[0];
|
|
8847
|
+
if (!id) return null;
|
|
8848
|
+
const el = ctx.store.getById(id);
|
|
8849
|
+
if (!el || el.locked || el.type !== "template" || el.templateShape !== "rectangle") return null;
|
|
8850
|
+
const zoom = ctx.camera.zoom;
|
|
8851
|
+
const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING2) / zoom;
|
|
8852
|
+
const cos = Math.cos(el.angle);
|
|
8853
|
+
const sin = Math.sin(el.angle);
|
|
8854
|
+
const halfW = (el.width ?? 0) / 2;
|
|
8855
|
+
const hx = el.position.x + el.radius / 2 * cos + halfW * -sin;
|
|
8856
|
+
const hy = el.position.y + el.radius / 2 * sin + halfW * cos;
|
|
8857
|
+
const dx = world.x - hx;
|
|
8858
|
+
const dy = world.y - hy;
|
|
8859
|
+
return dx * dx + dy * dy <= r * r ? { elementId: id } : null;
|
|
8860
|
+
}
|
|
8683
8861
|
function findElementsInRect(marquee, ctx) {
|
|
8684
8862
|
const candidates = ctx.store.queryRect(marquee);
|
|
8685
8863
|
const ids = [];
|
|
@@ -8834,6 +9012,34 @@ function computeTemplateResize(el, world, opts) {
|
|
|
8834
9012
|
}
|
|
8835
9013
|
return updates;
|
|
8836
9014
|
}
|
|
9015
|
+
function computeRectangleLengthResize(el, world, opts) {
|
|
9016
|
+
const cos = Math.cos(el.angle);
|
|
9017
|
+
const sin = Math.sin(el.angle);
|
|
9018
|
+
let len = (world.x - el.position.x) * cos + (world.y - el.position.y) * sin;
|
|
9019
|
+
if (opts.snapToGrid && opts.gridSize && opts.gridSize > 0) {
|
|
9020
|
+
const snapUnit = opts.gridType === "hex" ? Math.sqrt(3) * opts.gridSize : opts.gridSize;
|
|
9021
|
+
len = Math.max(snapUnit, Math.round(len / snapUnit) * snapUnit);
|
|
9022
|
+
}
|
|
9023
|
+
len = Math.max(MIN_ELEMENT_SIZE, len);
|
|
9024
|
+
const updates = { radius: len };
|
|
9025
|
+
if (el.feetPerCell != null && opts.gridSize && opts.gridSize > 0) {
|
|
9026
|
+
const snapUnit = opts.gridType === "hex" ? Math.sqrt(3) * opts.gridSize : opts.gridSize;
|
|
9027
|
+
updates.radiusFeet = len / snapUnit * el.feetPerCell;
|
|
9028
|
+
}
|
|
9029
|
+
return updates;
|
|
9030
|
+
}
|
|
9031
|
+
function computeRectangleWidthResize(el, world, opts) {
|
|
9032
|
+
const cos = Math.cos(el.angle);
|
|
9033
|
+
const sin = Math.sin(el.angle);
|
|
9034
|
+
const perp = Math.abs(-(world.x - el.position.x) * sin + (world.y - el.position.y) * cos);
|
|
9035
|
+
let width = perp * 2;
|
|
9036
|
+
if (opts.snapToGrid && opts.gridSize && opts.gridSize > 0) {
|
|
9037
|
+
const snapUnit = opts.gridType === "hex" ? Math.sqrt(3) * opts.gridSize : opts.gridSize;
|
|
9038
|
+
width = Math.max(snapUnit, Math.round(width / snapUnit) * snapUnit);
|
|
9039
|
+
}
|
|
9040
|
+
width = Math.max(MIN_ELEMENT_SIZE, width);
|
|
9041
|
+
return { width };
|
|
9042
|
+
}
|
|
8837
9043
|
|
|
8838
9044
|
// src/tools/select-tool.ts
|
|
8839
9045
|
var SNAP_PX = 6;
|
|
@@ -8929,6 +9135,18 @@ var SelectTool = class {
|
|
|
8929
9135
|
ctx.requestRender();
|
|
8930
9136
|
return;
|
|
8931
9137
|
}
|
|
9138
|
+
const rectLengthHit = hitTestRectangleLengthHandle(world, ctx, this._selectedIds);
|
|
9139
|
+
if (rectLengthHit) {
|
|
9140
|
+
this.mode = { type: "resizing-rect-length", elementId: rectLengthHit.elementId };
|
|
9141
|
+
ctx.requestRender();
|
|
9142
|
+
return;
|
|
9143
|
+
}
|
|
9144
|
+
const rectWidthHit = hitTestRectangleWidthHandle(world, ctx, this._selectedIds);
|
|
9145
|
+
if (rectWidthHit) {
|
|
9146
|
+
this.mode = { type: "resizing-rect-width", elementId: rectWidthHit.elementId };
|
|
9147
|
+
ctx.requestRender();
|
|
9148
|
+
return;
|
|
9149
|
+
}
|
|
8932
9150
|
const aimHit = hitTestTemplateAimHandle(world, ctx, this._selectedIds);
|
|
8933
9151
|
if (aimHit) {
|
|
8934
9152
|
this.mode = { type: "aiming-template", elementId: aimHit.elementId };
|
|
@@ -9029,6 +9247,19 @@ var SelectTool = class {
|
|
|
9029
9247
|
}
|
|
9030
9248
|
return;
|
|
9031
9249
|
}
|
|
9250
|
+
if (this.mode.type === "resizing-rect-length" || this.mode.type === "resizing-rect-width") {
|
|
9251
|
+
ctx.setCursor?.(this.mode.type === "resizing-rect-length" ? "ew-resize" : "ns-resize");
|
|
9252
|
+
const el = ctx.store.getById(this.mode.elementId);
|
|
9253
|
+
if (el && el.type === "template" && !el.locked) {
|
|
9254
|
+
const opts = { snapToGrid: ctx.snapToGrid, gridSize: ctx.gridSize, gridType: ctx.gridType };
|
|
9255
|
+
const patch = this.mode.type === "resizing-rect-length" ? computeRectangleLengthResize(el, world, opts) : computeRectangleWidthResize(el, world, opts);
|
|
9256
|
+
if (patch) {
|
|
9257
|
+
ctx.store.update(this.mode.elementId, patch);
|
|
9258
|
+
ctx.requestRender();
|
|
9259
|
+
}
|
|
9260
|
+
}
|
|
9261
|
+
return;
|
|
9262
|
+
}
|
|
9032
9263
|
if (this.mode.type === "rotating") {
|
|
9033
9264
|
const { elementId, center: center2, startPointerAngle, startRotation } = this.mode;
|
|
9034
9265
|
const a = Math.atan2(world.y - center2.y, world.x - center2.x);
|
|
@@ -9235,6 +9466,14 @@ var SelectTool = class {
|
|
|
9235
9466
|
ctx.setCursor?.("nwse-resize");
|
|
9236
9467
|
return null;
|
|
9237
9468
|
}
|
|
9469
|
+
if (hitTestRectangleLengthHandle(world, ctx, this._selectedIds)) {
|
|
9470
|
+
ctx.setCursor?.("ew-resize");
|
|
9471
|
+
return null;
|
|
9472
|
+
}
|
|
9473
|
+
if (hitTestRectangleWidthHandle(world, ctx, this._selectedIds)) {
|
|
9474
|
+
ctx.setCursor?.("ns-resize");
|
|
9475
|
+
return null;
|
|
9476
|
+
}
|
|
9238
9477
|
if (hitTestTemplateAimHandle(world, ctx, this._selectedIds)) {
|
|
9239
9478
|
ctx.setCursor?.("grab");
|
|
9240
9479
|
return null;
|
|
@@ -9899,6 +10138,11 @@ var MeasureTool = class {
|
|
|
9899
10138
|
};
|
|
9900
10139
|
|
|
9901
10140
|
// src/tools/template-tool.ts
|
|
10141
|
+
var MIN_RECT_WIDTH = 20;
|
|
10142
|
+
function defaultRectWidth(radius, scaleUnit) {
|
|
10143
|
+
if (scaleUnit > 0) return scaleUnit;
|
|
10144
|
+
return Math.max(MIN_RECT_WIDTH, radius * 0.25);
|
|
10145
|
+
}
|
|
9902
10146
|
var TemplateTool = class {
|
|
9903
10147
|
name = "template";
|
|
9904
10148
|
drawing = false;
|
|
@@ -9977,11 +10221,13 @@ var TemplateTool = class {
|
|
|
9977
10221
|
const snapUnit = gridSize && gridSize > 0 ? ctx.gridType === "hex" ? Math.sqrt(3) * gridSize : gridSize : 0;
|
|
9978
10222
|
const cells = snapUnit > 0 ? radius / snapUnit : 0;
|
|
9979
10223
|
const radiusFeet = cells * this.feetPerCell;
|
|
10224
|
+
const width = this.templateShape === "rectangle" ? defaultRectWidth(radius, this.feetScaleUnit) : void 0;
|
|
9980
10225
|
const element = createTemplate({
|
|
9981
10226
|
position: { ...this.origin },
|
|
9982
10227
|
templateShape: this.templateShape,
|
|
9983
10228
|
radius,
|
|
9984
10229
|
angle,
|
|
10230
|
+
width,
|
|
9985
10231
|
fillColor: this.fillColor,
|
|
9986
10232
|
strokeColor: this.strokeColor,
|
|
9987
10233
|
strokeWidth: this.strokeWidth,
|
|
@@ -10056,6 +10302,22 @@ var TemplateTool = class {
|
|
|
10056
10302
|
ctx.stroke();
|
|
10057
10303
|
break;
|
|
10058
10304
|
}
|
|
10305
|
+
case "rectangle": {
|
|
10306
|
+
const halfW = defaultRectWidth(radius, this.feetScaleUnit) / 2;
|
|
10307
|
+
const cos = Math.cos(angle);
|
|
10308
|
+
const sin = Math.sin(angle);
|
|
10309
|
+
const perpX = -sin * halfW;
|
|
10310
|
+
const perpY = cos * halfW;
|
|
10311
|
+
ctx.beginPath();
|
|
10312
|
+
ctx.moveTo(cx + perpX, cy + perpY);
|
|
10313
|
+
ctx.lineTo(cx + radius * cos + perpX, cy + radius * sin + perpY);
|
|
10314
|
+
ctx.lineTo(cx + radius * cos - perpX, cy + radius * sin - perpY);
|
|
10315
|
+
ctx.lineTo(cx - perpX, cy - perpY);
|
|
10316
|
+
ctx.closePath();
|
|
10317
|
+
ctx.fill();
|
|
10318
|
+
ctx.stroke();
|
|
10319
|
+
break;
|
|
10320
|
+
}
|
|
10059
10321
|
}
|
|
10060
10322
|
this.drawFeetLabel(ctx, radius);
|
|
10061
10323
|
ctx.restore();
|
|
@@ -10082,6 +10344,18 @@ var TemplateTool = class {
|
|
|
10082
10344
|
case "square":
|
|
10083
10345
|
hexCells = getHexCellsInSquare(center2, radiusCells, cellSize, orientation);
|
|
10084
10346
|
break;
|
|
10347
|
+
case "rectangle": {
|
|
10348
|
+
const widthCells = defaultRectWidth(radius, this.feetScaleUnit) / snapUnit;
|
|
10349
|
+
hexCells = getHexCellsInRectangle(
|
|
10350
|
+
center2,
|
|
10351
|
+
angle,
|
|
10352
|
+
radiusCells,
|
|
10353
|
+
widthCells,
|
|
10354
|
+
cellSize,
|
|
10355
|
+
orientation
|
|
10356
|
+
);
|
|
10357
|
+
break;
|
|
10358
|
+
}
|
|
10085
10359
|
}
|
|
10086
10360
|
ctx.save();
|
|
10087
10361
|
ctx.globalAlpha = 0.4;
|
|
@@ -10098,7 +10372,7 @@ var TemplateTool = class {
|
|
|
10098
10372
|
ctx.strokeStyle = this.strokeColor;
|
|
10099
10373
|
ctx.lineWidth = this.strokeWidth;
|
|
10100
10374
|
ctx.stroke();
|
|
10101
|
-
if (this.templateShape === "cone" || this.templateShape === "line" || this.templateShape === "circle" || this.templateShape === "square") {
|
|
10375
|
+
if (this.templateShape === "cone" || this.templateShape === "line" || this.templateShape === "circle" || this.templateShape === "square" || this.templateShape === "rectangle") {
|
|
10102
10376
|
ctx.globalAlpha = 0.5;
|
|
10103
10377
|
ctx.beginPath();
|
|
10104
10378
|
drawHexPath(ctx, center2.x, center2.y, cellSize, orientation);
|
|
@@ -10266,7 +10540,7 @@ var LaserTool = class {
|
|
|
10266
10540
|
};
|
|
10267
10541
|
|
|
10268
10542
|
// src/index.ts
|
|
10269
|
-
var VERSION = "0.
|
|
10543
|
+
var VERSION = "0.48.0";
|
|
10270
10544
|
// Annotate the CommonJS export names for ESM import in node:
|
|
10271
10545
|
0 && (module.exports = {
|
|
10272
10546
|
ArrowTool,
|
|
@@ -10318,6 +10592,7 @@ var VERSION = "0.47.0";
|
|
|
10318
10592
|
getHexCellsInCone,
|
|
10319
10593
|
getHexCellsInLine,
|
|
10320
10594
|
getHexCellsInRadius,
|
|
10595
|
+
getHexCellsInRectangle,
|
|
10321
10596
|
getHexCellsInSquare,
|
|
10322
10597
|
getHexDistance,
|
|
10323
10598
|
isNearBezier,
|