@fieldnotes/core 0.46.0 → 0.47.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 +156 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +156 -64
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1057,6 +1057,7 @@ declare class TemplateTool implements Tool {
|
|
|
1057
1057
|
private gridType;
|
|
1058
1058
|
private hexOrientation;
|
|
1059
1059
|
private snapEnabled;
|
|
1060
|
+
private feetScaleUnit;
|
|
1060
1061
|
private templateShape;
|
|
1061
1062
|
private fillColor;
|
|
1062
1063
|
private strokeColor;
|
|
@@ -1078,6 +1079,7 @@ declare class TemplateTool implements Tool {
|
|
|
1078
1079
|
private renderHexOverlay;
|
|
1079
1080
|
private computeRadius;
|
|
1080
1081
|
private computeAngle;
|
|
1082
|
+
private drawFeetLabel;
|
|
1081
1083
|
private snapToGrid;
|
|
1082
1084
|
private notifyOptionsChange;
|
|
1083
1085
|
}
|
|
@@ -1113,6 +1115,6 @@ declare class LaserTool implements Tool {
|
|
|
1113
1115
|
private notifyOptionsChange;
|
|
1114
1116
|
}
|
|
1115
1117
|
|
|
1116
|
-
declare const VERSION = "0.
|
|
1118
|
+
declare const VERSION = "0.47.0";
|
|
1117
1119
|
|
|
1118
1120
|
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
package/dist/index.d.ts
CHANGED
|
@@ -1057,6 +1057,7 @@ declare class TemplateTool implements Tool {
|
|
|
1057
1057
|
private gridType;
|
|
1058
1058
|
private hexOrientation;
|
|
1059
1059
|
private snapEnabled;
|
|
1060
|
+
private feetScaleUnit;
|
|
1060
1061
|
private templateShape;
|
|
1061
1062
|
private fillColor;
|
|
1062
1063
|
private strokeColor;
|
|
@@ -1078,6 +1079,7 @@ declare class TemplateTool implements Tool {
|
|
|
1078
1079
|
private renderHexOverlay;
|
|
1079
1080
|
private computeRadius;
|
|
1080
1081
|
private computeAngle;
|
|
1082
|
+
private drawFeetLabel;
|
|
1081
1083
|
private snapToGrid;
|
|
1082
1084
|
private notifyOptionsChange;
|
|
1083
1085
|
}
|
|
@@ -1113,6 +1115,6 @@ declare class LaserTool implements Tool {
|
|
|
1113
1115
|
private notifyOptionsChange;
|
|
1114
1116
|
}
|
|
1115
1117
|
|
|
1116
|
-
declare const VERSION = "0.
|
|
1118
|
+
declare const VERSION = "0.47.0";
|
|
1117
1119
|
|
|
1118
1120
|
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
package/dist/index.js
CHANGED
|
@@ -612,8 +612,20 @@ var InputFilter = class _InputFilter {
|
|
|
612
612
|
|
|
613
613
|
// src/elements/create-id.ts
|
|
614
614
|
var counter = 0;
|
|
615
|
+
function randomClientComponent() {
|
|
616
|
+
if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
|
|
617
|
+
const bytes = new Uint8Array(8);
|
|
618
|
+
crypto.getRandomValues(bytes);
|
|
619
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
620
|
+
}
|
|
621
|
+
return Math.random().toString(36).slice(2, 14);
|
|
622
|
+
}
|
|
623
|
+
var CLIENT = randomClientComponent();
|
|
624
|
+
function formatId(prefix, time, counter2, client) {
|
|
625
|
+
return `${prefix}_${time}_${counter2}_${client}`;
|
|
626
|
+
}
|
|
615
627
|
function createId(prefix) {
|
|
616
|
-
return
|
|
628
|
+
return formatId(prefix, Date.now().toString(36), (counter++).toString(36), CLIENT);
|
|
617
629
|
}
|
|
618
630
|
|
|
619
631
|
// src/core/geometry.ts
|
|
@@ -3226,6 +3238,48 @@ function drawHexPath(ctx, cx, cy, cellSize, orientation) {
|
|
|
3226
3238
|
ctx.closePath();
|
|
3227
3239
|
}
|
|
3228
3240
|
|
|
3241
|
+
// src/elements/renderers/template-measure.ts
|
|
3242
|
+
function renderTemplateFeetLabel(ctx, p) {
|
|
3243
|
+
if (p.feet <= 0) return;
|
|
3244
|
+
const directional = p.templateShape === "cone" || p.templateShape === "line";
|
|
3245
|
+
const dir = directional ? p.angle : 0;
|
|
3246
|
+
const length = p.templateShape === "square" ? p.radius / 2 : p.radius;
|
|
3247
|
+
const cos = Math.cos(dir);
|
|
3248
|
+
const sin = Math.sin(dir);
|
|
3249
|
+
const start = p.position;
|
|
3250
|
+
const end = { x: start.x + length * cos, y: start.y + length * sin };
|
|
3251
|
+
const midX = start.x + length / 2 * cos;
|
|
3252
|
+
const midY = start.y + length / 2 * sin;
|
|
3253
|
+
ctx.save();
|
|
3254
|
+
ctx.globalAlpha = 1;
|
|
3255
|
+
ctx.beginPath();
|
|
3256
|
+
ctx.setLineDash([4, 4]);
|
|
3257
|
+
ctx.strokeStyle = p.color;
|
|
3258
|
+
ctx.lineWidth = 1.5;
|
|
3259
|
+
ctx.moveTo(start.x, start.y);
|
|
3260
|
+
ctx.lineTo(end.x, end.y);
|
|
3261
|
+
ctx.stroke();
|
|
3262
|
+
ctx.setLineDash([]);
|
|
3263
|
+
const label = `${Math.round(p.feet)} ft`;
|
|
3264
|
+
const fontSize = Math.max(10, Math.min(14, p.radius * 0.15));
|
|
3265
|
+
ctx.font = `bold ${fontSize}px system-ui, sans-serif`;
|
|
3266
|
+
ctx.textAlign = "center";
|
|
3267
|
+
ctx.textBaseline = "bottom";
|
|
3268
|
+
const textY = midY - 4;
|
|
3269
|
+
const metrics = ctx.measureText(label);
|
|
3270
|
+
const padX = 4;
|
|
3271
|
+
const padY = 2;
|
|
3272
|
+
const textW = metrics.width + padX * 2;
|
|
3273
|
+
const textH = fontSize + padY * 2;
|
|
3274
|
+
ctx.fillStyle = "rgba(255, 255, 255, 0.85)";
|
|
3275
|
+
ctx.beginPath();
|
|
3276
|
+
ctx.roundRect(midX - textW / 2, textY - textH, textW, textH, 3);
|
|
3277
|
+
ctx.fill();
|
|
3278
|
+
ctx.fillStyle = p.color;
|
|
3279
|
+
ctx.fillText(label, midX, textY - padY);
|
|
3280
|
+
ctx.restore();
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3229
3283
|
// src/elements/renderers/template-renderer.ts
|
|
3230
3284
|
function renderTemplate(ctx, template, store) {
|
|
3231
3285
|
const grid = store?.getElementsByType("grid")[0];
|
|
@@ -3249,9 +3303,6 @@ function renderGeometricTemplate(ctx, template) {
|
|
|
3249
3303
|
ctx.arc(cx, cy, r, 0, Math.PI * 2);
|
|
3250
3304
|
ctx.fill();
|
|
3251
3305
|
ctx.stroke();
|
|
3252
|
-
if (template.radiusFeet != null && template.radiusFeet > 0) {
|
|
3253
|
-
renderRadiusMarker(ctx, cx, cy, r, template.radiusFeet);
|
|
3254
|
-
}
|
|
3255
3306
|
break;
|
|
3256
3307
|
case "square":
|
|
3257
3308
|
ctx.fillRect(cx - r / 2, cy - r / 2, r, r);
|
|
@@ -3284,6 +3335,16 @@ function renderGeometricTemplate(ctx, template) {
|
|
|
3284
3335
|
break;
|
|
3285
3336
|
}
|
|
3286
3337
|
}
|
|
3338
|
+
if (template.radiusFeet != null && template.radiusFeet > 0) {
|
|
3339
|
+
renderTemplateFeetLabel(ctx, {
|
|
3340
|
+
position: template.position,
|
|
3341
|
+
radius: template.radius,
|
|
3342
|
+
angle: template.angle,
|
|
3343
|
+
templateShape: template.templateShape,
|
|
3344
|
+
feet: template.radiusFeet,
|
|
3345
|
+
color: template.strokeColor
|
|
3346
|
+
});
|
|
3347
|
+
}
|
|
3287
3348
|
ctx.restore();
|
|
3288
3349
|
}
|
|
3289
3350
|
function renderHexTemplate(ctx, template, cellSize, orientation) {
|
|
@@ -3330,44 +3391,18 @@ function renderHexTemplate(ctx, template, cellSize, orientation) {
|
|
|
3330
3391
|
ctx.lineWidth = template.strokeWidth;
|
|
3331
3392
|
ctx.stroke();
|
|
3332
3393
|
}
|
|
3333
|
-
if (template.
|
|
3334
|
-
|
|
3335
|
-
|
|
3394
|
+
if (template.radiusFeet != null && template.radiusFeet > 0) {
|
|
3395
|
+
renderTemplateFeetLabel(ctx, {
|
|
3396
|
+
position: template.position,
|
|
3397
|
+
radius: template.radius,
|
|
3398
|
+
angle: template.angle,
|
|
3399
|
+
templateShape: template.templateShape,
|
|
3400
|
+
feet: template.radiusFeet,
|
|
3401
|
+
color: template.strokeColor
|
|
3402
|
+
});
|
|
3336
3403
|
}
|
|
3337
3404
|
ctx.restore();
|
|
3338
3405
|
}
|
|
3339
|
-
function renderRadiusMarker(ctx, cx, cy, r, feet) {
|
|
3340
|
-
const markerColor = ctx.strokeStyle;
|
|
3341
|
-
ctx.save();
|
|
3342
|
-
ctx.globalAlpha = 1;
|
|
3343
|
-
ctx.beginPath();
|
|
3344
|
-
ctx.setLineDash([4, 4]);
|
|
3345
|
-
ctx.strokeStyle = markerColor;
|
|
3346
|
-
ctx.lineWidth = 1.5;
|
|
3347
|
-
ctx.moveTo(cx, cy);
|
|
3348
|
-
ctx.lineTo(cx + r, cy);
|
|
3349
|
-
ctx.stroke();
|
|
3350
|
-
ctx.setLineDash([]);
|
|
3351
|
-
const label = `${Math.round(feet)} ft`;
|
|
3352
|
-
const fontSize = Math.max(10, Math.min(14, r * 0.15));
|
|
3353
|
-
ctx.font = `bold ${fontSize}px system-ui, sans-serif`;
|
|
3354
|
-
ctx.textAlign = "center";
|
|
3355
|
-
ctx.textBaseline = "bottom";
|
|
3356
|
-
const textX = cx + r / 2;
|
|
3357
|
-
const textY = cy - 4;
|
|
3358
|
-
const metrics = ctx.measureText(label);
|
|
3359
|
-
const padX = 4;
|
|
3360
|
-
const padY = 2;
|
|
3361
|
-
const textW = metrics.width + padX * 2;
|
|
3362
|
-
const textH = fontSize + padY * 2;
|
|
3363
|
-
ctx.fillStyle = "rgba(255, 255, 255, 0.85)";
|
|
3364
|
-
ctx.beginPath();
|
|
3365
|
-
ctx.roundRect(textX - textW / 2, textY - textH, textW, textH, 3);
|
|
3366
|
-
ctx.fill();
|
|
3367
|
-
ctx.fillStyle = markerColor;
|
|
3368
|
-
ctx.fillText(label, textX, textY - padY);
|
|
3369
|
-
ctx.restore();
|
|
3370
|
-
}
|
|
3371
3406
|
|
|
3372
3407
|
// src/elements/grid-renderer.ts
|
|
3373
3408
|
function getSquareGridLines(bounds, cellSize) {
|
|
@@ -8213,6 +8248,20 @@ function getOverlayLayout(el, zoom) {
|
|
|
8213
8248
|
const rotateHandle = rotatePoint(topMid, center2, angle);
|
|
8214
8249
|
return { center: center2, corners, rotateHandle, angle };
|
|
8215
8250
|
}
|
|
8251
|
+
function templateAimKnob(el, zoom) {
|
|
8252
|
+
if (el.type !== "template") return null;
|
|
8253
|
+
if (el.templateShape !== "cone" && el.templateShape !== "line") return null;
|
|
8254
|
+
const gap = ROTATE_HANDLE_OFFSET / zoom;
|
|
8255
|
+
const dist = el.radius + gap;
|
|
8256
|
+
const origin = el.position;
|
|
8257
|
+
return {
|
|
8258
|
+
origin,
|
|
8259
|
+
knob: {
|
|
8260
|
+
x: origin.x + dist * Math.cos(el.angle),
|
|
8261
|
+
y: origin.y + dist * Math.sin(el.angle)
|
|
8262
|
+
}
|
|
8263
|
+
};
|
|
8264
|
+
}
|
|
8216
8265
|
function getHandlePositions(bounds) {
|
|
8217
8266
|
return [
|
|
8218
8267
|
["nw", { x: bounds.x, y: bounds.y }],
|
|
@@ -8361,6 +8410,22 @@ function renderSelectionBoxes(ctx, p) {
|
|
|
8361
8410
|
handleWorldSize
|
|
8362
8411
|
);
|
|
8363
8412
|
ctx.setLineDash([4 / zoom, 4 / zoom]);
|
|
8413
|
+
if (p.selectedIds.length === 1 && (el.templateShape === "cone" || el.templateShape === "line")) {
|
|
8414
|
+
const aim = templateAimKnob(el, zoom);
|
|
8415
|
+
if (aim) {
|
|
8416
|
+
ctx.beginPath();
|
|
8417
|
+
ctx.moveTo(aim.origin.x, aim.origin.y);
|
|
8418
|
+
ctx.lineTo(aim.knob.x, aim.knob.y);
|
|
8419
|
+
ctx.stroke();
|
|
8420
|
+
ctx.setLineDash([]);
|
|
8421
|
+
ctx.fillStyle = "#ffffff";
|
|
8422
|
+
ctx.beginPath();
|
|
8423
|
+
ctx.arc(aim.knob.x, aim.knob.y, handleWorldSize / 2, 0, Math.PI * 2);
|
|
8424
|
+
ctx.fill();
|
|
8425
|
+
ctx.stroke();
|
|
8426
|
+
ctx.setLineDash([4 / zoom, 4 / zoom]);
|
|
8427
|
+
}
|
|
8428
|
+
}
|
|
8364
8429
|
}
|
|
8365
8430
|
if (p.selectedIds.length === 1 && ROTATABLE_TYPES.has(el.type)) {
|
|
8366
8431
|
const stemStart = topMidpoint(layout);
|
|
@@ -8516,6 +8581,19 @@ function hitTestTemplateResizeHandle(world, ctx, selectedIds) {
|
|
|
8516
8581
|
}
|
|
8517
8582
|
return null;
|
|
8518
8583
|
}
|
|
8584
|
+
function hitTestTemplateAimHandle(world, ctx, selectedIds) {
|
|
8585
|
+
if (selectedIds.length !== 1) return null;
|
|
8586
|
+
const id = selectedIds[0];
|
|
8587
|
+
if (!id) return null;
|
|
8588
|
+
const el = ctx.store.getById(id);
|
|
8589
|
+
if (!el || el.locked) return null;
|
|
8590
|
+
const knob = templateAimKnob(el, ctx.camera.zoom);
|
|
8591
|
+
if (!knob) return null;
|
|
8592
|
+
const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING2) / ctx.camera.zoom;
|
|
8593
|
+
const dx = world.x - knob.knob.x;
|
|
8594
|
+
const dy = world.y - knob.knob.y;
|
|
8595
|
+
return dx * dx + dy * dy <= r * r ? { elementId: id } : null;
|
|
8596
|
+
}
|
|
8519
8597
|
function findElementsInRect(marquee, ctx) {
|
|
8520
8598
|
const candidates = ctx.store.queryRect(marquee);
|
|
8521
8599
|
const ids = [];
|
|
@@ -8765,6 +8843,12 @@ var SelectTool = class {
|
|
|
8765
8843
|
ctx.requestRender();
|
|
8766
8844
|
return;
|
|
8767
8845
|
}
|
|
8846
|
+
const aimHit = hitTestTemplateAimHandle(world, ctx, this._selectedIds);
|
|
8847
|
+
if (aimHit) {
|
|
8848
|
+
this.mode = { type: "aiming-template", elementId: aimHit.elementId };
|
|
8849
|
+
ctx.requestRender();
|
|
8850
|
+
return;
|
|
8851
|
+
}
|
|
8768
8852
|
const rotateHit = hitTestRotateHandle(world, ctx, this._selectedIds);
|
|
8769
8853
|
if (rotateHit) {
|
|
8770
8854
|
const el = ctx.store.getById(rotateHit.elementId);
|
|
@@ -8846,6 +8930,19 @@ var SelectTool = class {
|
|
|
8846
8930
|
this.handleTemplateResize(world, ctx);
|
|
8847
8931
|
return;
|
|
8848
8932
|
}
|
|
8933
|
+
if (this.mode.type === "aiming-template") {
|
|
8934
|
+
const el = ctx.store.getById(this.mode.elementId);
|
|
8935
|
+
if (el && el.type === "template" && !el.locked) {
|
|
8936
|
+
let a = Math.atan2(world.y - el.position.y, world.x - el.position.x);
|
|
8937
|
+
if (state.shiftKey) {
|
|
8938
|
+
const snap = ctx.gridType === "hex" ? Math.PI / 3 : ROTATE_SNAP;
|
|
8939
|
+
a = Math.round(a / snap) * snap;
|
|
8940
|
+
}
|
|
8941
|
+
ctx.store.update(this.mode.elementId, { angle: normalizeAngle(a) });
|
|
8942
|
+
ctx.requestRender();
|
|
8943
|
+
}
|
|
8944
|
+
return;
|
|
8945
|
+
}
|
|
8849
8946
|
if (this.mode.type === "rotating") {
|
|
8850
8947
|
const { elementId, center: center2, startPointerAngle, startRotation } = this.mode;
|
|
8851
8948
|
const a = Math.atan2(world.y - center2.y, world.x - center2.x);
|
|
@@ -9052,6 +9149,10 @@ var SelectTool = class {
|
|
|
9052
9149
|
ctx.setCursor?.("nwse-resize");
|
|
9053
9150
|
return null;
|
|
9054
9151
|
}
|
|
9152
|
+
if (hitTestTemplateAimHandle(world, ctx, this._selectedIds)) {
|
|
9153
|
+
ctx.setCursor?.("grab");
|
|
9154
|
+
return null;
|
|
9155
|
+
}
|
|
9055
9156
|
if (hitTestRotateHandle(world, ctx, this._selectedIds)) {
|
|
9056
9157
|
ctx.setCursor?.("grab");
|
|
9057
9158
|
return null;
|
|
@@ -9721,6 +9822,7 @@ var TemplateTool = class {
|
|
|
9721
9822
|
gridType;
|
|
9722
9823
|
hexOrientation;
|
|
9723
9824
|
snapEnabled = false;
|
|
9825
|
+
feetScaleUnit = 0;
|
|
9724
9826
|
templateShape;
|
|
9725
9827
|
fillColor;
|
|
9726
9828
|
strokeColor;
|
|
@@ -9769,6 +9871,7 @@ var TemplateTool = class {
|
|
|
9769
9871
|
this.gridType = ctx.gridType;
|
|
9770
9872
|
this.hexOrientation = ctx.hexOrientation;
|
|
9771
9873
|
this.snapEnabled = !!ctx.gridType || (ctx.snapToGrid ?? false);
|
|
9874
|
+
this.feetScaleUnit = ctx.gridSize && ctx.gridSize > 0 ? ctx.gridType === "hex" ? Math.sqrt(3) * ctx.gridSize : ctx.gridSize : 0;
|
|
9772
9875
|
const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
9773
9876
|
this.origin = this.snapToGrid(world, ctx);
|
|
9774
9877
|
this.current = { ...this.origin };
|
|
@@ -9868,6 +9971,7 @@ var TemplateTool = class {
|
|
|
9868
9971
|
break;
|
|
9869
9972
|
}
|
|
9870
9973
|
}
|
|
9974
|
+
this.drawFeetLabel(ctx, radius);
|
|
9871
9975
|
ctx.restore();
|
|
9872
9976
|
}
|
|
9873
9977
|
renderHexOverlay(ctx, radius) {
|
|
@@ -9918,30 +10022,7 @@ var TemplateTool = class {
|
|
|
9918
10022
|
ctx.lineWidth = this.strokeWidth;
|
|
9919
10023
|
ctx.stroke();
|
|
9920
10024
|
}
|
|
9921
|
-
|
|
9922
|
-
const feet = radiusCells * this.feetPerCell;
|
|
9923
|
-
if (feet > 0) {
|
|
9924
|
-
ctx.globalAlpha = 1;
|
|
9925
|
-
const label = `${Math.round(feet)} ft`;
|
|
9926
|
-
const fontSize = Math.max(10, Math.min(14, radius * 0.15));
|
|
9927
|
-
ctx.font = `bold ${fontSize}px system-ui, sans-serif`;
|
|
9928
|
-
ctx.textAlign = "center";
|
|
9929
|
-
ctx.textBaseline = "bottom";
|
|
9930
|
-
const textX = center2.x;
|
|
9931
|
-
const textY = center2.y - 4;
|
|
9932
|
-
const metrics = ctx.measureText(label);
|
|
9933
|
-
const padX = 4;
|
|
9934
|
-
const padY = 2;
|
|
9935
|
-
const textW = metrics.width + padX * 2;
|
|
9936
|
-
const textH = fontSize + padY * 2;
|
|
9937
|
-
ctx.fillStyle = "rgba(255, 255, 255, 0.85)";
|
|
9938
|
-
ctx.beginPath();
|
|
9939
|
-
ctx.roundRect(textX - textW / 2, textY - textH, textW, textH, 3);
|
|
9940
|
-
ctx.fill();
|
|
9941
|
-
ctx.fillStyle = this.strokeColor;
|
|
9942
|
-
ctx.fillText(label, textX, textY - padY);
|
|
9943
|
-
}
|
|
9944
|
-
}
|
|
10025
|
+
this.drawFeetLabel(ctx, radius);
|
|
9945
10026
|
ctx.restore();
|
|
9946
10027
|
}
|
|
9947
10028
|
computeRadius() {
|
|
@@ -9959,6 +10040,17 @@ var TemplateTool = class {
|
|
|
9959
10040
|
const dy = this.current.y - this.origin.y;
|
|
9960
10041
|
return Math.atan2(dy, dx);
|
|
9961
10042
|
}
|
|
10043
|
+
drawFeetLabel(ctx, radius) {
|
|
10044
|
+
const feet = this.feetScaleUnit > 0 ? radius / this.feetScaleUnit * this.feetPerCell : 0;
|
|
10045
|
+
renderTemplateFeetLabel(ctx, {
|
|
10046
|
+
position: this.origin,
|
|
10047
|
+
radius,
|
|
10048
|
+
angle: this.computeAngle(),
|
|
10049
|
+
templateShape: this.templateShape,
|
|
10050
|
+
feet,
|
|
10051
|
+
color: this.strokeColor
|
|
10052
|
+
});
|
|
10053
|
+
}
|
|
9962
10054
|
snapToGrid(point, ctx) {
|
|
9963
10055
|
if (!ctx.gridSize) return point;
|
|
9964
10056
|
if (ctx.gridType === "hex" && ctx.hexOrientation) {
|
|
@@ -10088,7 +10180,7 @@ var LaserTool = class {
|
|
|
10088
10180
|
};
|
|
10089
10181
|
|
|
10090
10182
|
// src/index.ts
|
|
10091
|
-
var VERSION = "0.
|
|
10183
|
+
var VERSION = "0.47.0";
|
|
10092
10184
|
export {
|
|
10093
10185
|
ArrowTool,
|
|
10094
10186
|
AutoSave,
|