@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 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") return null;
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
- const hx = bounds.x + bounds.w;
8485
- const hy = bounds.y + bounds.h;
8486
- ctx.fillRect(
8487
- hx - handleWorldSize / 2,
8488
- hy - handleWorldSize / 2,
8489
- handleWorldSize,
8490
- handleWorldSize
8491
- );
8492
- ctx.strokeRect(
8493
- hx - handleWorldSize / 2,
8494
- hy - handleWorldSize / 2,
8495
- handleWorldSize,
8496
- handleWorldSize
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.47.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,