@reekon-tools/boldr-utils 1.15.2 → 1.15.3
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.
|
@@ -13,7 +13,7 @@ const PLANE_GRID_COLOR = '#FFD1F8';
|
|
|
13
13
|
const PLANE_GRID_OPACITY = 0.9;
|
|
14
14
|
// Doc-space stroke widths (scale with zoom, like the drawn shapes).
|
|
15
15
|
const PLANE_GRID_WIDTH = 2.5;
|
|
16
|
-
const PLANE_OUTLINE_WIDTH =
|
|
16
|
+
const PLANE_OUTLINE_WIDTH = 14;
|
|
17
17
|
// Cross-tick half-length (doc units) marking the ends of a scale-mode
|
|
18
18
|
// reference line, so it reads as "a measured span", not just a line.
|
|
19
19
|
const REF_TICK_LEN = 18;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PlaneCalibration, PlaneCalibrationMode } from '../../../types/annotation.js';
|
|
1
|
+
import type { PlacedMeasurementRef, PlaneCalibration, PlaneCalibrationMode } from '../../../types/annotation.js';
|
|
2
2
|
import type { Tool } from '../Tool.js';
|
|
3
3
|
export interface PlaneToolOptions {
|
|
4
4
|
id?: string;
|
|
@@ -7,6 +7,7 @@ export interface PlaneToolOptions {
|
|
|
7
7
|
onPlaced?(plane: PlaneCalibration): void;
|
|
8
8
|
onInvalidQuad?(): void;
|
|
9
9
|
onExistingPlane?(): void;
|
|
10
|
+
onDimensionTileTap?(tile: PlacedMeasurementRef): void;
|
|
10
11
|
minDragPx?: number;
|
|
11
12
|
}
|
|
12
13
|
export declare const createPlaneTool: (options: PlaneToolOptions) => Tool;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_LAYER_ID } from '../../../types/annotation.js';
|
|
2
2
|
import { isQuadConvexNonDegenerate, normalizeQuadOrder, planeEdgeLine, } from '../planeGeometry.js';
|
|
3
3
|
import { linePosOf, recomputeAnchor, DEFAULT_LINE_POS, } from '../measurementGeometry.js';
|
|
4
|
+
import { stampTileDims } from '../stampLayout.js';
|
|
4
5
|
import { FormulaColors } from '../../../theme/colors.js';
|
|
5
6
|
// Screen-px grab radius for an existing plane's corner/endpoint handles while
|
|
6
7
|
// the tool is active (matches the drawn handle affordance scale).
|
|
@@ -53,10 +54,10 @@ const buildDimensionTile = (doc, plane, edge) => {
|
|
|
53
54
|
planeId: plane.id,
|
|
54
55
|
planeEdge: edge,
|
|
55
56
|
// The tile's line IS the plane edge PlaneElement already draws — style it
|
|
56
|
-
// as the same
|
|
57
|
-
// painting the default measurement blue on top of it.
|
|
57
|
+
// as the same purple stroke (and width) so it disappears into the outline
|
|
58
|
+
// instead of painting the default measurement blue on top of it.
|
|
58
59
|
lineColor: PLANE_COLOR,
|
|
59
|
-
lineWidth:
|
|
60
|
+
lineWidth: 14,
|
|
60
61
|
showLabel: true,
|
|
61
62
|
showValue: true,
|
|
62
63
|
createdAt: Date.now(),
|
|
@@ -192,6 +193,29 @@ export const createPlaneTool = (options) => {
|
|
|
192
193
|
ctx.commit({ ops });
|
|
193
194
|
options.onPlaced?.(plane);
|
|
194
195
|
};
|
|
196
|
+
// Which committed-plane DIMENSION tile a tap landed on, if any — the tile
|
|
197
|
+
// BOX only (deliberately not the edge line, which spans the whole side and
|
|
198
|
+
// would turn every edge tap into value entry). Same footprint the overlay
|
|
199
|
+
// draws and the select tool grabs (stampTileDims + the ctx scale factors).
|
|
200
|
+
const hitDimensionTile = (ctx, world) => {
|
|
201
|
+
const plane = committedPlane(ctx.document);
|
|
202
|
+
if (!plane)
|
|
203
|
+
return null;
|
|
204
|
+
const zoom = ctx.viewport.state.zoom;
|
|
205
|
+
for (let i = ctx.document.placedMeasurements.length - 1; i >= 0; i--) {
|
|
206
|
+
const m = ctx.document.placedMeasurements[i];
|
|
207
|
+
if (m.planeId !== plane.id || !m.planeEdge)
|
|
208
|
+
continue;
|
|
209
|
+
const dims = stampTileDims(m, ctx.tileScaleFactor, ctx.tileViewportScale, ctx.headerTileScaleFactor, ctx.fileTileScaleFactor);
|
|
210
|
+
const halfW = (dims.width / 2 + 6) / zoom;
|
|
211
|
+
const halfH = (dims.height / 2 + 6) / zoom;
|
|
212
|
+
if (Math.abs(world.x - m.anchor.x) <= halfW &&
|
|
213
|
+
Math.abs(world.y - m.anchor.y) <= halfH) {
|
|
214
|
+
return m;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
};
|
|
195
219
|
// Which committed-plane handle a press landed on, if any.
|
|
196
220
|
const hitHandle = (ctx, world) => {
|
|
197
221
|
const plane = committedPlane(ctx.document);
|
|
@@ -300,9 +324,19 @@ export const createPlaneTool = (options) => {
|
|
|
300
324
|
});
|
|
301
325
|
return;
|
|
302
326
|
}
|
|
303
|
-
//
|
|
304
|
-
//
|
|
327
|
+
// While a calibration exists, a TAP on one of its dimension tiles
|
|
328
|
+
// selects it and opens value entry (the host's onDimensionTileTap) —
|
|
329
|
+
// dimensions stay editable without leaving calibration mode. Any other
|
|
330
|
+
// attempt to mark new geometry is blocked: delete the plane first.
|
|
331
|
+
// (A real drag — scale mode with `moved` — is never a tile tap.)
|
|
305
332
|
if (committedPlane(ctx.document)) {
|
|
333
|
+
const isTap = s.kind !== 'plane-scale-drawing' || !s.moved;
|
|
334
|
+
const tile = isTap ? hitDimensionTile(ctx, event.world) : null;
|
|
335
|
+
if (tile) {
|
|
336
|
+
ctx.setSelection({ ids: [tile.id] });
|
|
337
|
+
options.onDimensionTileTap?.(tile);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
306
340
|
options.onExistingPlane?.();
|
|
307
341
|
return;
|
|
308
342
|
}
|
|
@@ -772,6 +772,10 @@ export const useAnnotationCanvasState = (props) => {
|
|
|
772
772
|
// Build one remove op per selected element, dispatched by which
|
|
773
773
|
// collection owns the id. A single multi-op commit makes the whole
|
|
774
774
|
// deletion one undo step (inverse re-adds each element).
|
|
775
|
+
// Plane DIMENSION tiles (planeEdge) are exempt: they are the
|
|
776
|
+
// calibration's entry affordances and live and die with it
|
|
777
|
+
// (removePlane / the plane tool's replace flow) — their value is
|
|
778
|
+
// replaced by re-entering it, never by deleting the tile.
|
|
775
779
|
const ops = [
|
|
776
780
|
...doc.strokes
|
|
777
781
|
.filter((s) => idSet.has(s.id))
|
|
@@ -780,7 +784,7 @@ export const useAnnotationCanvasState = (props) => {
|
|
|
780
784
|
.filter((s) => idSet.has(s.id))
|
|
781
785
|
.map((s) => ({ op: 'removeShape', id: s.id })),
|
|
782
786
|
...doc.placedMeasurements
|
|
783
|
-
.filter((m) => idSet.has(m.id))
|
|
787
|
+
.filter((m) => idSet.has(m.id) && !m.planeEdge)
|
|
784
788
|
.map((m) => ({ op: 'removeMeasurement', id: m.id })),
|
|
785
789
|
];
|
|
786
790
|
if (ops.length === 0)
|