@reekon-tools/boldr-utils 1.6.18 → 1.6.19
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/annotation/canvas/AnnotationCanvasInner.js +7 -1
- package/dist/annotation/canvas/AnnotationCanvasInner.native.js +58 -5
- package/dist/annotation/canvas/AnnotationCanvasSkia.d.ts +5 -1
- package/dist/annotation/canvas/AnnotationCanvasSkia.js +53 -4
- package/dist/annotation/canvas/Tool.d.ts +5 -2
- package/dist/annotation/canvas/measurementGeometry.d.ts +1 -1
- package/dist/annotation/canvas/measurementGeometry.js +3 -2
- package/dist/annotation/canvas/stampLayout.d.ts +7 -1
- package/dist/annotation/canvas/stampLayout.js +66 -5
- package/dist/annotation/canvas/tools/measurementLineTool.d.ts +12 -0
- package/dist/annotation/canvas/tools/measurementLineTool.js +95 -0
- package/dist/annotation/canvas/tools/panTool.js +1 -1
- package/dist/annotation/canvas/tools/selectTool.js +75 -9
- package/dist/annotation/canvas/useAnnotationCanvasState.d.ts +1 -0
- package/dist/annotation/canvas/useAnnotationCanvasState.js +9 -0
- package/dist/exports.d.ts +1 -0
- package/dist/exports.js +1 -0
- package/dist/types/annotation.d.ts +4 -0
- package/dist/types/annotation.js +6 -0
- package/dist/types/firestore.d.ts +53 -0
- package/dist/types/firestore.js +49 -0
- package/package.json +1 -1
- package/dist/canvas/AnnotationCanvas.d.ts +0 -11
- package/dist/canvas/AnnotationCanvas.js +0 -10
- package/dist/canvas/AnnotationCanvas.native.d.ts +0 -8
- package/dist/canvas/AnnotationCanvas.native.js +0 -6
- package/dist/canvas/AnnotationCanvasInner.d.ts +0 -39
- package/dist/canvas/AnnotationCanvasInner.js +0 -219
- package/dist/canvas/AnnotationCanvasInner.native.d.ts +0 -35
- package/dist/canvas/AnnotationCanvasInner.native.js +0 -138
- package/dist/canvas/AnnotationCanvasSkia.d.ts +0 -27
- package/dist/canvas/AnnotationCanvasSkia.js +0 -20
- package/dist/canvas/Tool.d.ts +0 -38
- package/dist/canvas/Tool.js +0 -1
- package/dist/canvas/elements/BackgroundImageElement.d.ts +0 -9
- package/dist/canvas/elements/BackgroundImageElement.js +0 -37
- package/dist/canvas/elements/MeasurementStampElement.d.ts +0 -13
- package/dist/canvas/elements/MeasurementStampElement.js +0 -30
- package/dist/canvas/elements/ShapeElement.d.ts +0 -7
- package/dist/canvas/elements/ShapeElement.js +0 -62
- package/dist/canvas/elements/StrokeElement.d.ts +0 -7
- package/dist/canvas/elements/StrokeElement.js +0 -18
- package/dist/canvas/measurementPicker.d.ts +0 -10
- package/dist/canvas/measurementPicker.js +0 -1
- package/dist/canvas/measurementStampOverlay.d.ts +0 -11
- package/dist/canvas/measurementStampOverlay.js +0 -1
- package/dist/canvas/pointerAdapter.d.ts +0 -3
- package/dist/canvas/pointerAdapter.js +0 -19
- package/dist/canvas/stampLayout.d.ts +0 -5
- package/dist/canvas/stampLayout.js +0 -14
- package/dist/canvas/tools/measurementStampTool.d.ts +0 -9
- package/dist/canvas/tools/measurementStampTool.js +0 -37
- package/dist/canvas/tools/panTool.d.ts +0 -5
- package/dist/canvas/tools/panTool.js +0 -25
- package/dist/canvas/tools/penTool.d.ts +0 -13
- package/dist/canvas/tools/penTool.js +0 -68
- package/dist/canvas/tools/selectTool.d.ts +0 -2
- package/dist/canvas/tools/selectTool.js +0 -182
- package/dist/canvas/useAnnotationCanvasState.d.ts +0 -54
- package/dist/canvas/useAnnotationCanvasState.js +0 -210
- package/dist/canvas/viewport.d.ts +0 -16
- package/dist/canvas/viewport.js +0 -54
- package/dist/data/AnnotationDataContext.d.ts +0 -8
- package/dist/data/AnnotationDataContext.js +0 -11
- package/dist/data/AnnotationDataProvider.d.ts +0 -65
- package/dist/data/AnnotationDataProvider.js +0 -4
- package/dist/data/InMemoryAnnotationProvider.d.ts +0 -30
- package/dist/data/InMemoryAnnotationProvider.js +0 -197
- package/dist/data/canvasPersistence.d.ts +0 -3
- package/dist/data/canvasPersistence.js +0 -26
- package/dist/data/hooks/useAnnotationCanvasDoc.d.ts +0 -33
- package/dist/data/hooks/useAnnotationCanvasDoc.js +0 -314
- package/dist/data/hooks/useAnnotationDoc.d.ts +0 -7
- package/dist/data/hooks/useAnnotationDoc.js +0 -33
- package/dist/data/hooks/useAnnotationList.d.ts +0 -7
- package/dist/data/hooks/useAnnotationList.js +0 -26
- package/dist/data/hooks/useAnnotationMutations.d.ts +0 -9
- package/dist/data/hooks/useAnnotationMutations.js +0 -11
- package/dist/hooks/useParseMeasurement.d.ts +0 -4
- package/dist/hooks/useParseMeasurement.js +0 -14
- package/dist/utils/evaluateFormula.d.ts +0 -20
- package/dist/utils/evaluateFormula.js +0 -31
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useFont } from '@shopify/react-native-skia';
|
|
3
|
-
import { useCallback, useEffect, useRef, } from 'react';
|
|
4
|
-
import { AnnotationCanvasSkia } from './AnnotationCanvasSkia.js';
|
|
5
|
-
import { useAnnotationCanvasState, } from './useAnnotationCanvasState.js';
|
|
6
|
-
import { STAMP_TILE_SIZE } from './stampLayout.js';
|
|
7
|
-
const DEFAULT_PAN_TRIGGERS = ['middleMouse', 'space'];
|
|
8
|
-
export const AnnotationCanvasInner = (props) => {
|
|
9
|
-
const { fallbackUnit, fractionalTolerance, decimalTolerance, resolveImageUrl, stampFontSource, stampValueFontSize = 14, stampLabelFontSize = 11, gestures, width, height, style, activeToolId, tools, } = props;
|
|
10
|
-
const wheelMode = gestures?.wheel ?? 'auto';
|
|
11
|
-
const panTriggers = gestures?.panTriggers ?? DEFAULT_PAN_TRIGGERS;
|
|
12
|
-
const allowSpacePan = panTriggers.includes('space');
|
|
13
|
-
const allowMiddlePan = panTriggers.includes('middleMouse');
|
|
14
|
-
const allowRightPan = panTriggers.includes('rightMouse');
|
|
15
|
-
const valueFont = useFont(stampFontSource, stampValueFontSize);
|
|
16
|
-
const labelFont = useFont(stampFontSource, stampLabelFontSize);
|
|
17
|
-
const state = useAnnotationCanvasState(props);
|
|
18
|
-
const containerRef = useRef(null);
|
|
19
|
-
const panGestureRef = useRef(null);
|
|
20
|
-
const spaceDownRef = useRef(false);
|
|
21
|
-
const activeTool = tools.find((t) => t.id === activeToolId) ?? null;
|
|
22
|
-
const toCanvasPointer = useCallback((event) => {
|
|
23
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
24
|
-
const screen = {
|
|
25
|
-
x: event.clientX - (rect?.left ?? 0),
|
|
26
|
-
y: event.clientY - (rect?.top ?? 0),
|
|
27
|
-
};
|
|
28
|
-
return {
|
|
29
|
-
pointerId: event.pointerId,
|
|
30
|
-
screen,
|
|
31
|
-
world: state.ctx.viewport.screenToWorld(screen),
|
|
32
|
-
pressure: event.pressure || undefined,
|
|
33
|
-
shiftKey: event.shiftKey,
|
|
34
|
-
altKey: event.altKey,
|
|
35
|
-
metaKey: event.metaKey,
|
|
36
|
-
ctrlKey: event.ctrlKey,
|
|
37
|
-
};
|
|
38
|
-
}, [state.ctx.viewport]);
|
|
39
|
-
const isPanTriggerDown = useCallback((event) => {
|
|
40
|
-
if (allowMiddlePan && event.button === 1)
|
|
41
|
-
return true;
|
|
42
|
-
if (allowRightPan && event.button === 2)
|
|
43
|
-
return true;
|
|
44
|
-
if (allowSpacePan && event.button === 0 && spaceDownRef.current)
|
|
45
|
-
return true;
|
|
46
|
-
return false;
|
|
47
|
-
}, [allowMiddlePan, allowRightPan, allowSpacePan]);
|
|
48
|
-
const handlePointerDown = useCallback((event) => {
|
|
49
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
50
|
-
const screen = {
|
|
51
|
-
x: event.clientX - (rect?.left ?? 0),
|
|
52
|
-
y: event.clientY - (rect?.top ?? 0),
|
|
53
|
-
};
|
|
54
|
-
if (isPanTriggerDown(event)) {
|
|
55
|
-
panGestureRef.current = { pointerId: event.pointerId, lastScreen: screen };
|
|
56
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
57
|
-
event.preventDefault();
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
61
|
-
state.dispatchPointerDown(toCanvasPointer(event));
|
|
62
|
-
}, [state, toCanvasPointer, isPanTriggerDown]);
|
|
63
|
-
const handlePointerMove = useCallback((event) => {
|
|
64
|
-
const pan = panGestureRef.current;
|
|
65
|
-
if (pan && event.pointerId === pan.pointerId) {
|
|
66
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
67
|
-
const screen = {
|
|
68
|
-
x: event.clientX - (rect?.left ?? 0),
|
|
69
|
-
y: event.clientY - (rect?.top ?? 0),
|
|
70
|
-
};
|
|
71
|
-
state.pan({
|
|
72
|
-
x: screen.x - pan.lastScreen.x,
|
|
73
|
-
y: screen.y - pan.lastScreen.y,
|
|
74
|
-
});
|
|
75
|
-
panGestureRef.current = { pointerId: pan.pointerId, lastScreen: screen };
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
state.dispatchPointerMove(toCanvasPointer(event));
|
|
79
|
-
}, [state, toCanvasPointer]);
|
|
80
|
-
const handlePointerUp = useCallback((event) => {
|
|
81
|
-
const pan = panGestureRef.current;
|
|
82
|
-
if (pan && event.pointerId === pan.pointerId) {
|
|
83
|
-
panGestureRef.current = null;
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
state.dispatchPointerUp(toCanvasPointer(event));
|
|
87
|
-
}, [state, toCanvasPointer]);
|
|
88
|
-
const handlePointerCancel = useCallback(() => {
|
|
89
|
-
panGestureRef.current = null;
|
|
90
|
-
state.dispatchPointerCancel();
|
|
91
|
-
}, [state]);
|
|
92
|
-
const handleWheel = useCallback((event) => {
|
|
93
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
94
|
-
const focal = {
|
|
95
|
-
x: event.clientX - (rect?.left ?? 0),
|
|
96
|
-
y: event.clientY - (rect?.top ?? 0),
|
|
97
|
-
};
|
|
98
|
-
if (event.ctrlKey || event.metaKey) {
|
|
99
|
-
const factor = Math.exp(-event.deltaY / 200);
|
|
100
|
-
state.zoom(focal, state.ctx.viewport.state.zoom * factor);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (wheelMode === 'zoom') {
|
|
104
|
-
const factor = Math.exp(-event.deltaY / 300);
|
|
105
|
-
state.zoom(focal, state.ctx.viewport.state.zoom * factor);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
if (event.shiftKey) {
|
|
109
|
-
state.pan({ x: event.deltaY, y: event.deltaX });
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
state.pan({ x: event.deltaX, y: event.deltaY });
|
|
113
|
-
}, [state, wheelMode]);
|
|
114
|
-
const handleContextMenu = useCallback((event) => {
|
|
115
|
-
if (allowRightPan)
|
|
116
|
-
event.preventDefault();
|
|
117
|
-
}, [allowRightPan]);
|
|
118
|
-
useEffect(() => {
|
|
119
|
-
const el = containerRef.current;
|
|
120
|
-
if (!el)
|
|
121
|
-
return;
|
|
122
|
-
const stop = (e) => {
|
|
123
|
-
if (e.target === el || el.contains(e.target)) {
|
|
124
|
-
e.preventDefault();
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
el.addEventListener('wheel', stop, { passive: false });
|
|
128
|
-
return () => el.removeEventListener('wheel', stop);
|
|
129
|
-
}, []);
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
if (!allowSpacePan)
|
|
132
|
-
return;
|
|
133
|
-
const onKeyDown = (e) => {
|
|
134
|
-
if (e.code === 'Space' && !e.repeat) {
|
|
135
|
-
spaceDownRef.current = true;
|
|
136
|
-
if (containerRef.current)
|
|
137
|
-
containerRef.current.style.cursor = 'grab';
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
const onKeyUp = (e) => {
|
|
141
|
-
if (e.code === 'Space') {
|
|
142
|
-
spaceDownRef.current = false;
|
|
143
|
-
if (containerRef.current)
|
|
144
|
-
containerRef.current.style.cursor = '';
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
window.addEventListener('keydown', onKeyDown);
|
|
148
|
-
window.addEventListener('keyup', onKeyUp);
|
|
149
|
-
return () => {
|
|
150
|
-
window.removeEventListener('keydown', onKeyDown);
|
|
151
|
-
window.removeEventListener('keyup', onKeyUp);
|
|
152
|
-
};
|
|
153
|
-
}, [allowSpacePan]);
|
|
154
|
-
const containerStyle = {
|
|
155
|
-
position: 'relative',
|
|
156
|
-
width,
|
|
157
|
-
height,
|
|
158
|
-
overflow: 'hidden',
|
|
159
|
-
touchAction: 'none',
|
|
160
|
-
userSelect: 'none',
|
|
161
|
-
cursor: activeTool?.cursor ?? 'default',
|
|
162
|
-
...style,
|
|
163
|
-
};
|
|
164
|
-
const customPreview = activeTool?.renderPreview?.(state.customPreviewState, state.ctx);
|
|
165
|
-
const { renderMeasurementStamp, selection } = props;
|
|
166
|
-
return (_jsxs("div", { ref: containerRef, style: containerStyle, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, onPointerCancel: handlePointerCancel, onWheel: handleWheel, onContextMenu: handleContextMenu, children: [AnnotationCanvasSkia({
|
|
167
|
-
width,
|
|
168
|
-
height,
|
|
169
|
-
effectiveCanvas: state.effectiveCanvas,
|
|
170
|
-
worldTransform: state.worldTransform,
|
|
171
|
-
measurementsById: state.measurementsById,
|
|
172
|
-
fallbackUnit,
|
|
173
|
-
fractionalTolerance,
|
|
174
|
-
decimalTolerance,
|
|
175
|
-
resolveImageUrl,
|
|
176
|
-
valueFont,
|
|
177
|
-
labelFont,
|
|
178
|
-
hideMeasurementStamps: !!renderMeasurementStamp,
|
|
179
|
-
penDrawingStroke: state.penDrawingStroke,
|
|
180
|
-
customPreview,
|
|
181
|
-
}), renderMeasurementStamp && (_jsx("div", { style: {
|
|
182
|
-
position: 'absolute',
|
|
183
|
-
inset: 0,
|
|
184
|
-
pointerEvents: 'none',
|
|
185
|
-
}, children: state.effectiveCanvas.placedMeasurements.map((placed) => {
|
|
186
|
-
const size = STAMP_TILE_SIZE * (placed.scale ?? 1);
|
|
187
|
-
const cx = (placed.anchor.x - state.viewport.pan.x) * state.viewport.zoom;
|
|
188
|
-
const cy = (placed.anchor.y - state.viewport.pan.y) * state.viewport.zoom;
|
|
189
|
-
const isSelected = selection?.ids.includes(placed.id) ?? false;
|
|
190
|
-
return (_jsxs("div", { style: {
|
|
191
|
-
position: 'absolute',
|
|
192
|
-
left: 0,
|
|
193
|
-
top: 0,
|
|
194
|
-
width: size,
|
|
195
|
-
height: size,
|
|
196
|
-
transform: `translate(${cx - size / 2}px, ${cy - size / 2}px)`,
|
|
197
|
-
}, children: [renderMeasurementStamp({
|
|
198
|
-
placed,
|
|
199
|
-
measurement: state.measurementsById.get(placed.measurementId) ?? null,
|
|
200
|
-
selected: isSelected,
|
|
201
|
-
size,
|
|
202
|
-
zoom: state.viewport.zoom,
|
|
203
|
-
}), isSelected && (_jsx("div", { role: "button", "aria-label": "Remove measurement", onPointerDown: (e) => {
|
|
204
|
-
e.stopPropagation();
|
|
205
|
-
state.ctx.commit({
|
|
206
|
-
ops: [{ op: 'removeMeasurement', id: placed.id }],
|
|
207
|
-
});
|
|
208
|
-
state.ctx.setSelection(null);
|
|
209
|
-
}, style: {
|
|
210
|
-
position: 'absolute',
|
|
211
|
-
top: -10,
|
|
212
|
-
right: -10,
|
|
213
|
-
width: 40,
|
|
214
|
-
height: 40,
|
|
215
|
-
cursor: 'pointer',
|
|
216
|
-
pointerEvents: 'auto',
|
|
217
|
-
} }))] }, placed.id));
|
|
218
|
-
}) }))] }));
|
|
219
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { type MutableRefObject } from 'react';
|
|
2
|
-
import { type ViewStyle } from 'react-native';
|
|
3
|
-
import type { RenderMeasurementStamp } from './measurementStampOverlay.js';
|
|
4
|
-
import type { DecimalTolerance, FractionalTolerance, Measurement, Units } from '../types/firestore.js';
|
|
5
|
-
import type { AnnotationCanvasState, AnnotationDocumentPatch, Selection } from '../types/annotation.js';
|
|
6
|
-
import type { MeasurementRef } from './measurementPicker.js';
|
|
7
|
-
import type { Tool } from './Tool.js';
|
|
8
|
-
import { type AnnotationCanvasHandle } from './useAnnotationCanvasState.js';
|
|
9
|
-
import type { ViewportState } from './viewport.js';
|
|
10
|
-
export type { AnnotationCanvasHandle };
|
|
11
|
-
export interface AnnotationCanvasInnerProps {
|
|
12
|
-
canvas: AnnotationCanvasState;
|
|
13
|
-
onCommit(patch: AnnotationDocumentPatch): void;
|
|
14
|
-
tools: Tool[];
|
|
15
|
-
activeToolId: string;
|
|
16
|
-
selection: Selection | null;
|
|
17
|
-
onSelectionChange(selection: Selection | null): void;
|
|
18
|
-
measurements?: Measurement[];
|
|
19
|
-
fallbackUnit?: Units;
|
|
20
|
-
fractionalTolerance?: FractionalTolerance;
|
|
21
|
-
decimalTolerance?: DecimalTolerance;
|
|
22
|
-
resolveImageUrl?: (storagePath: string) => Promise<string>;
|
|
23
|
-
pickMeasurement?: () => Promise<MeasurementRef | null>;
|
|
24
|
-
renderMeasurementStamp?: RenderMeasurementStamp;
|
|
25
|
-
stampFontSource?: unknown;
|
|
26
|
-
stampValueFontSize?: number;
|
|
27
|
-
stampLabelFontSize?: number;
|
|
28
|
-
gestures?: unknown;
|
|
29
|
-
width: number;
|
|
30
|
-
height: number;
|
|
31
|
-
initialViewport?: ViewportState;
|
|
32
|
-
style?: ViewStyle;
|
|
33
|
-
imperativeRef?: MutableRefObject<AnnotationCanvasHandle | null>;
|
|
34
|
-
}
|
|
35
|
-
export declare const AnnotationCanvasInner: (props: AnnotationCanvasInnerProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useFont } from '@shopify/react-native-skia';
|
|
3
|
-
import { useMemo, useRef } from 'react';
|
|
4
|
-
import { StyleSheet, TouchableOpacity, View } from 'react-native';
|
|
5
|
-
import { Gesture, GestureDetector, GestureHandlerRootView, } from 'react-native-gesture-handler';
|
|
6
|
-
import { STAMP_TILE_SIZE } from './stampLayout.js';
|
|
7
|
-
import { AnnotationCanvasSkia } from './AnnotationCanvasSkia.js';
|
|
8
|
-
import { useAnnotationCanvasState, } from './useAnnotationCanvasState.js';
|
|
9
|
-
// Native fingerprint: one finger drives the active tool, two fingers
|
|
10
|
-
// pan/zoom the viewport. Tap counts as a brief pointer down+up so tools
|
|
11
|
-
// like measurement-stamp (which only listen to onPointerUp) work via tap.
|
|
12
|
-
export const AnnotationCanvasInner = (props) => {
|
|
13
|
-
const { fallbackUnit, fractionalTolerance, decimalTolerance, resolveImageUrl, stampFontSource, stampValueFontSize = 14, stampLabelFontSize = 11, width, height, style, } = props;
|
|
14
|
-
const valueFont = useFont(stampFontSource, stampValueFontSize);
|
|
15
|
-
const labelFont = useFont(stampFontSource, stampLabelFontSize);
|
|
16
|
-
const state = useAnnotationCanvasState(props);
|
|
17
|
-
// Per-gesture refs so we always emit a matching down/move/up sequence.
|
|
18
|
-
const pointerIdRef = useRef(1);
|
|
19
|
-
const inFlightRef = useRef(null);
|
|
20
|
-
const pinchStartZoomRef = useRef(1);
|
|
21
|
-
const buildEvent = (pointerId, screen) => ({
|
|
22
|
-
pointerId,
|
|
23
|
-
screen,
|
|
24
|
-
world: state.ctx.viewport.screenToWorld(screen),
|
|
25
|
-
});
|
|
26
|
-
const gesture = useMemo(() => {
|
|
27
|
-
const toolPan = Gesture.Pan()
|
|
28
|
-
.minPointers(1)
|
|
29
|
-
.maxPointers(1)
|
|
30
|
-
.runOnJS(true)
|
|
31
|
-
.onBegin((e) => {
|
|
32
|
-
const id = pointerIdRef.current++;
|
|
33
|
-
const screen = { x: e.x, y: e.y };
|
|
34
|
-
inFlightRef.current = { id, lastScreen: screen };
|
|
35
|
-
state.dispatchPointerDown(buildEvent(id, screen));
|
|
36
|
-
})
|
|
37
|
-
.onUpdate((e) => {
|
|
38
|
-
const f = inFlightRef.current;
|
|
39
|
-
if (!f)
|
|
40
|
-
return;
|
|
41
|
-
const screen = { x: e.x, y: e.y };
|
|
42
|
-
f.lastScreen = screen;
|
|
43
|
-
state.dispatchPointerMove(buildEvent(f.id, screen));
|
|
44
|
-
})
|
|
45
|
-
.onEnd((e) => {
|
|
46
|
-
const f = inFlightRef.current;
|
|
47
|
-
if (!f)
|
|
48
|
-
return;
|
|
49
|
-
state.dispatchPointerUp(buildEvent(f.id, { x: e.x, y: e.y }));
|
|
50
|
-
inFlightRef.current = null;
|
|
51
|
-
})
|
|
52
|
-
.onFinalize(() => {
|
|
53
|
-
if (inFlightRef.current) {
|
|
54
|
-
state.dispatchPointerCancel();
|
|
55
|
-
inFlightRef.current = null;
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
const tap = Gesture.Tap()
|
|
59
|
-
.maxDuration(250)
|
|
60
|
-
.runOnJS(true)
|
|
61
|
-
.onEnd((e) => {
|
|
62
|
-
const id = pointerIdRef.current++;
|
|
63
|
-
const screen = { x: e.x, y: e.y };
|
|
64
|
-
// Synthesize a down+up sequence so tools that only listen to
|
|
65
|
-
// onPointerUp (e.g. measurement stamp) still fire.
|
|
66
|
-
state.dispatchPointerDown(buildEvent(id, screen));
|
|
67
|
-
state.dispatchPointerUp(buildEvent(id, screen));
|
|
68
|
-
});
|
|
69
|
-
const viewportPan = Gesture.Pan()
|
|
70
|
-
.minPointers(2)
|
|
71
|
-
.maxPointers(2)
|
|
72
|
-
.runOnJS(true)
|
|
73
|
-
.onChange((e) => {
|
|
74
|
-
state.pan({ x: e.changeX, y: e.changeY });
|
|
75
|
-
});
|
|
76
|
-
const pinch = Gesture.Pinch()
|
|
77
|
-
.runOnJS(true)
|
|
78
|
-
.onBegin(() => {
|
|
79
|
-
pinchStartZoomRef.current = state.ctx.viewport.state.zoom;
|
|
80
|
-
})
|
|
81
|
-
.onUpdate((e) => {
|
|
82
|
-
state.zoom({ x: e.focalX, y: e.focalY }, pinchStartZoomRef.current * e.scale);
|
|
83
|
-
});
|
|
84
|
-
return Gesture.Race(tap, Gesture.Simultaneous(viewportPan, pinch), toolPan);
|
|
85
|
-
}, [state]);
|
|
86
|
-
const activeTool = props.tools.find((t) => t.id === props.activeToolId) ?? null;
|
|
87
|
-
const customPreview = activeTool?.renderPreview?.(state.customPreviewState, state.ctx);
|
|
88
|
-
const { renderMeasurementStamp, selection } = props;
|
|
89
|
-
return (_jsxs(GestureHandlerRootView, { style: [{ width, height }, style], children: [_jsx(GestureDetector, { gesture: gesture, children: _jsx(View, { style: { width, height }, collapsable: false, children: AnnotationCanvasSkia({
|
|
90
|
-
width,
|
|
91
|
-
height,
|
|
92
|
-
effectiveCanvas: state.effectiveCanvas,
|
|
93
|
-
worldTransform: state.worldTransform,
|
|
94
|
-
measurementsById: state.measurementsById,
|
|
95
|
-
fallbackUnit,
|
|
96
|
-
fractionalTolerance,
|
|
97
|
-
decimalTolerance,
|
|
98
|
-
resolveImageUrl,
|
|
99
|
-
valueFont,
|
|
100
|
-
labelFont,
|
|
101
|
-
hideMeasurementStamps: !!renderMeasurementStamp,
|
|
102
|
-
penDrawingStroke: state.penDrawingStroke,
|
|
103
|
-
customPreview,
|
|
104
|
-
}) }) }), renderMeasurementStamp && (_jsx(View, { pointerEvents: "box-none", style: StyleSheet.absoluteFill, children: state.effectiveCanvas.placedMeasurements.map((placed) => {
|
|
105
|
-
const size = STAMP_TILE_SIZE * (placed.scale ?? 1);
|
|
106
|
-
const cx = (placed.anchor.x - state.viewport.pan.x) * state.viewport.zoom;
|
|
107
|
-
const cy = (placed.anchor.y - state.viewport.pan.y) * state.viewport.zoom;
|
|
108
|
-
const isSelected = selection?.ids.includes(placed.id) ?? false;
|
|
109
|
-
return (_jsxs(View, { pointerEvents: "box-none", style: {
|
|
110
|
-
position: 'absolute',
|
|
111
|
-
left: 0,
|
|
112
|
-
top: 0,
|
|
113
|
-
width: size,
|
|
114
|
-
height: size,
|
|
115
|
-
transform: [
|
|
116
|
-
{ translateX: cx - size / 2 },
|
|
117
|
-
{ translateY: cy - size / 2 },
|
|
118
|
-
],
|
|
119
|
-
}, children: [_jsx(View, { pointerEvents: "none", style: StyleSheet.absoluteFill, children: renderMeasurementStamp({
|
|
120
|
-
placed,
|
|
121
|
-
measurement: state.measurementsById.get(placed.measurementId) ?? null,
|
|
122
|
-
selected: isSelected,
|
|
123
|
-
size,
|
|
124
|
-
zoom: state.viewport.zoom,
|
|
125
|
-
}) }), isSelected && (_jsx(TouchableOpacity, { accessibilityRole: "button", accessibilityLabel: "Remove measurement", hitSlop: 10, onPress: () => {
|
|
126
|
-
state.ctx.commit({
|
|
127
|
-
ops: [{ op: 'removeMeasurement', id: placed.id }],
|
|
128
|
-
});
|
|
129
|
-
state.ctx.setSelection(null);
|
|
130
|
-
}, style: {
|
|
131
|
-
position: 'absolute',
|
|
132
|
-
top: -8,
|
|
133
|
-
right: -8,
|
|
134
|
-
width: 36,
|
|
135
|
-
height: 36,
|
|
136
|
-
} }))] }, placed.id));
|
|
137
|
-
}) }))] }));
|
|
138
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { type SkFont } from '@shopify/react-native-skia';
|
|
2
|
-
import type { ReactNode } from 'react';
|
|
3
|
-
import type { AnnotationCanvasState, AnnotationStroke } from '../types/annotation.js';
|
|
4
|
-
import { DecimalTolerance, FractionalTolerance, Units, type Measurement } from '../types/firestore.js';
|
|
5
|
-
export interface AnnotationCanvasSkiaProps {
|
|
6
|
-
width: number;
|
|
7
|
-
height: number;
|
|
8
|
-
effectiveCanvas: AnnotationCanvasState;
|
|
9
|
-
worldTransform: Array<{
|
|
10
|
-
scale: number;
|
|
11
|
-
} | {
|
|
12
|
-
translateX: number;
|
|
13
|
-
} | {
|
|
14
|
-
translateY: number;
|
|
15
|
-
}>;
|
|
16
|
-
measurementsById: Map<string, Measurement>;
|
|
17
|
-
fallbackUnit?: Units;
|
|
18
|
-
fractionalTolerance?: FractionalTolerance;
|
|
19
|
-
decimalTolerance?: DecimalTolerance;
|
|
20
|
-
resolveImageUrl?: (storagePath: string) => Promise<string>;
|
|
21
|
-
valueFont: SkFont | null;
|
|
22
|
-
labelFont: SkFont | null;
|
|
23
|
-
hideMeasurementStamps?: boolean;
|
|
24
|
-
penDrawingStroke: AnnotationStroke | null;
|
|
25
|
-
customPreview?: ReactNode;
|
|
26
|
-
}
|
|
27
|
-
export declare const AnnotationCanvasSkia: ({ width, height, effectiveCanvas, worldTransform, measurementsById, fallbackUnit, fractionalTolerance, decimalTolerance, resolveImageUrl, valueFont, labelFont, hideMeasurementStamps, penDrawingStroke, customPreview, }: AnnotationCanvasSkiaProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Canvas, Group } from '@shopify/react-native-skia';
|
|
3
|
-
import { Units, } from '../types/firestore.js';
|
|
4
|
-
import { BackgroundImageElement } from './elements/BackgroundImageElement.js';
|
|
5
|
-
import { MeasurementStampElement } from './elements/MeasurementStampElement.js';
|
|
6
|
-
import { ShapeElement } from './elements/ShapeElement.js';
|
|
7
|
-
import { StrokeElement } from './elements/StrokeElement.js';
|
|
8
|
-
// Platform-agnostic Skia subtree shared by web and native Inners.
|
|
9
|
-
//
|
|
10
|
-
// Call this as a FUNCTION (`AnnotationCanvasSkia({ ... })`), not as a JSX
|
|
11
|
-
// component (`<AnnotationCanvasSkia ... />`). Used as a component, it adds
|
|
12
|
-
// a React component boundary between the parent and Skia's `<Canvas>` that
|
|
13
|
-
// breaks Skia's reconciler when the page first calls `useFont` — the JS
|
|
14
|
-
// thread hangs in `MakeFreeTypeFaceFromData`. Symptoms only appeared on
|
|
15
|
-
// Vite's dev server with a symlinked boldr-utils + React Refresh, but
|
|
16
|
-
// since the function-call pattern works identically on native we use it
|
|
17
|
-
// in both Inners for consistency. Don't add hooks here; this is a plain
|
|
18
|
-
// JSX-returning helper, not a component.
|
|
19
|
-
export const AnnotationCanvasSkia = ({ width, height, effectiveCanvas, worldTransform, measurementsById, fallbackUnit, fractionalTolerance, decimalTolerance, resolveImageUrl, valueFont, labelFont, hideMeasurementStamps, penDrawingStroke, customPreview, }) => (_jsx(Canvas, { style: { width, height }, children: _jsxs(Group, { transform: worldTransform, children: [effectiveCanvas.viewport.backgroundImage && (_jsx(BackgroundImageElement, { image: effectiveCanvas.viewport.backgroundImage, docWidth: effectiveCanvas.viewport.width, docHeight: effectiveCanvas.viewport.height, fit: effectiveCanvas.viewport.backgroundFit ?? 'contain', resolveUrl: resolveImageUrl })), effectiveCanvas.strokes.map((stroke) => (_jsx(StrokeElement, { stroke: stroke }, stroke.id))), effectiveCanvas.shapes.map((shape) => (_jsx(ShapeElement, { shape: shape, font: valueFont }, shape.id))), !hideMeasurementStamps &&
|
|
20
|
-
effectiveCanvas.placedMeasurements.map((placed) => (_jsx(MeasurementStampElement, { placed: placed, measurement: measurementsById.get(placed.measurementId) ?? null, fallbackUnit: fallbackUnit ?? Units.Millimeters, fractionalTolerance: fractionalTolerance, decimalTolerance: decimalTolerance, valueFont: valueFont, labelFont: labelFont }, placed.id))), penDrawingStroke && _jsx(StrokeElement, { stroke: penDrawingStroke }), customPreview] }) }));
|
package/dist/canvas/Tool.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { ReactNode, ComponentType } from 'react';
|
|
2
|
-
import type { AnnotationCanvasState, AnnotationDocumentPatch, AnnotationElement, Selection, Vec2 } from '../types/annotation.js';
|
|
3
|
-
import type { MeasurementRef } from './measurementPicker.js';
|
|
4
|
-
import type { ViewportApi } from './viewport.js';
|
|
5
|
-
export interface CanvasPointerEvent {
|
|
6
|
-
pointerId: number;
|
|
7
|
-
world: Vec2;
|
|
8
|
-
screen: Vec2;
|
|
9
|
-
pressure?: number;
|
|
10
|
-
shiftKey?: boolean;
|
|
11
|
-
altKey?: boolean;
|
|
12
|
-
metaKey?: boolean;
|
|
13
|
-
ctrlKey?: boolean;
|
|
14
|
-
}
|
|
15
|
-
export interface ToolContext {
|
|
16
|
-
document: AnnotationCanvasState;
|
|
17
|
-
selection: Selection | null;
|
|
18
|
-
viewport: ViewportApi;
|
|
19
|
-
preview(patch: AnnotationDocumentPatch): void;
|
|
20
|
-
commit(patch: AnnotationDocumentPatch): void;
|
|
21
|
-
setSelection(selection: Selection | null): void;
|
|
22
|
-
requestPickMeasurement(): Promise<MeasurementRef | null>;
|
|
23
|
-
applyPan(deltaScreen: Vec2): void;
|
|
24
|
-
applyZoom(focalScreen: Vec2, nextZoom: number): void;
|
|
25
|
-
}
|
|
26
|
-
export type ToolState = unknown;
|
|
27
|
-
export interface Tool {
|
|
28
|
-
id: string;
|
|
29
|
-
label: string;
|
|
30
|
-
icon?: ComponentType;
|
|
31
|
-
cursor?: string;
|
|
32
|
-
onPointerDown?(event: CanvasPointerEvent, ctx: ToolContext, state: ToolState): ToolState | void;
|
|
33
|
-
onPointerMove?(event: CanvasPointerEvent, ctx: ToolContext, state: ToolState): ToolState | void;
|
|
34
|
-
onPointerUp?(event: CanvasPointerEvent, ctx: ToolContext, state: ToolState): ToolState | void;
|
|
35
|
-
onCancel?(state: ToolState, ctx: ToolContext): void;
|
|
36
|
-
renderPreview?(state: ToolState, ctx: ToolContext): ReactNode;
|
|
37
|
-
hitTest?(element: AnnotationElement, worldPoint: Vec2): boolean;
|
|
38
|
-
}
|
package/dist/canvas/Tool.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { AnnotationBackgroundImage, BackgroundFit } from '../../types/annotation.js';
|
|
2
|
-
export interface BackgroundImageElementProps {
|
|
3
|
-
image: AnnotationBackgroundImage;
|
|
4
|
-
docWidth: number;
|
|
5
|
-
docHeight: number;
|
|
6
|
-
fit?: BackgroundFit;
|
|
7
|
-
resolveUrl?: (path: string) => Promise<string>;
|
|
8
|
-
}
|
|
9
|
-
export declare const BackgroundImageElement: ({ image, docWidth, docHeight, fit, resolveUrl, }: BackgroundImageElementProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Image, useImage } from '@shopify/react-native-skia';
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
4
|
-
const computeFit = (imgW, imgH, docW, docH, fit) => {
|
|
5
|
-
if (fit === 'stretch') {
|
|
6
|
-
return { x: 0, y: 0, width: docW, height: docH };
|
|
7
|
-
}
|
|
8
|
-
const scale = fit === 'cover'
|
|
9
|
-
? Math.max(docW / imgW, docH / imgH)
|
|
10
|
-
: Math.min(docW / imgW, docH / imgH);
|
|
11
|
-
const w = imgW * scale;
|
|
12
|
-
const h = imgH * scale;
|
|
13
|
-
return { x: (docW - w) / 2, y: (docH - h) / 2, width: w, height: h };
|
|
14
|
-
};
|
|
15
|
-
export const BackgroundImageElement = ({ image, docWidth, docHeight, fit = 'contain', resolveUrl, }) => {
|
|
16
|
-
const [url, setUrl] = useState(image.downloadUrl);
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
let cancelled = false;
|
|
19
|
-
if (resolveUrl) {
|
|
20
|
-
resolveUrl(image.storagePath).then((next) => {
|
|
21
|
-
if (!cancelled)
|
|
22
|
-
setUrl(next);
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
setUrl(image.downloadUrl);
|
|
27
|
-
}
|
|
28
|
-
return () => {
|
|
29
|
-
cancelled = true;
|
|
30
|
-
};
|
|
31
|
-
}, [image.downloadUrl, image.storagePath, resolveUrl]);
|
|
32
|
-
const skImage = useImage(url);
|
|
33
|
-
if (!skImage)
|
|
34
|
-
return null;
|
|
35
|
-
const dims = computeFit(image.widthPx, image.heightPx, docWidth, docHeight, fit);
|
|
36
|
-
return (_jsx(Image, { image: skImage, x: dims.x, y: dims.y, width: dims.width, height: dims.height, fit: "fill" }));
|
|
37
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { type SkFont } from '@shopify/react-native-skia';
|
|
2
|
-
import type { PlacedMeasurementRef } from '../../types/annotation.js';
|
|
3
|
-
import { DecimalTolerance, FractionalTolerance, type Measurement, type Units } from '../../types/firestore.js';
|
|
4
|
-
export interface MeasurementStampElementProps {
|
|
5
|
-
placed: PlacedMeasurementRef;
|
|
6
|
-
measurement: Measurement | null;
|
|
7
|
-
fallbackUnit: Units;
|
|
8
|
-
fractionalTolerance?: FractionalTolerance;
|
|
9
|
-
decimalTolerance?: DecimalTolerance;
|
|
10
|
-
valueFont?: SkFont | null;
|
|
11
|
-
labelFont?: SkFont | null;
|
|
12
|
-
}
|
|
13
|
-
export declare const MeasurementStampElement: ({ placed, measurement, fallbackUnit, fractionalTolerance, decimalTolerance, valueFont, labelFont, }: MeasurementStampElementProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Group, Line, RoundedRect, Text, } from '@shopify/react-native-skia';
|
|
3
|
-
import { DecimalTolerance, FractionalTolerance, } from '../../types/firestore.js';
|
|
4
|
-
import { convertMicrometers } from '../../utils/micrometersToUnit.js';
|
|
5
|
-
import { STAMP_HEIGHT, STAMP_PADDING_X, STAMP_PADDING_Y, STAMP_WIDTH, } from '../stampLayout.js';
|
|
6
|
-
const VALUE_FONT_BASELINE_OFFSET = 14;
|
|
7
|
-
const LABEL_FONT_BASELINE_OFFSET = 24;
|
|
8
|
-
const formatValue = (measurement, unit, fractionalTolerance, decimalTolerance) => {
|
|
9
|
-
if (!measurement)
|
|
10
|
-
return '—';
|
|
11
|
-
const result = convertMicrometers(measurement.value, unit, fractionalTolerance, decimalTolerance);
|
|
12
|
-
return `${result.value}${result.unit ? ` ${result.unit}` : ''}`;
|
|
13
|
-
};
|
|
14
|
-
export const MeasurementStampElement = ({ placed, measurement, fallbackUnit, fractionalTolerance = FractionalTolerance.Sixteenth, decimalTolerance = DecimalTolerance.Hundredth, valueFont, labelFont, }) => {
|
|
15
|
-
const unit = placed.unitOverride ?? measurement?.unit ?? fallbackUnit;
|
|
16
|
-
const valueText = formatValue(measurement, unit, fractionalTolerance, decimalTolerance);
|
|
17
|
-
const label = placed.labelOverride ??
|
|
18
|
-
measurement?.label ??
|
|
19
|
-
(measurement
|
|
20
|
-
? `M${measurement.measurementIndex ?? ''}`
|
|
21
|
-
: '');
|
|
22
|
-
const showLabel = placed.showLabel !== false && !!label;
|
|
23
|
-
const showValue = placed.showValue !== false;
|
|
24
|
-
const scale = placed.scale ?? 1;
|
|
25
|
-
// Fixed-size stamp — no measureText calls. Keeps rendering deterministic
|
|
26
|
-
// even when no font is loaded (browser/native both).
|
|
27
|
-
const baseX = placed.anchor.x - (STAMP_WIDTH * scale) / 2;
|
|
28
|
-
const baseY = placed.anchor.y - (STAMP_HEIGHT * scale) / 2;
|
|
29
|
-
return (_jsxs(Group, { transform: [{ translateX: baseX }, { translateY: baseY }, { scale }], children: [placed.leader && (_jsx(Line, { p1: placed.leader.from, p2: placed.leader.to, color: "#3B82F6", style: "stroke", strokeWidth: 1.5 })), _jsx(RoundedRect, { x: 0, y: 0, width: STAMP_WIDTH, height: STAMP_HEIGHT, r: 6, color: "#FFFFFFEE" }), _jsx(RoundedRect, { x: 0, y: 0, width: STAMP_WIDTH, height: STAMP_HEIGHT, r: 6, color: "#3B82F6", style: "stroke", strokeWidth: 1.25 }), showValue && valueFont && (_jsx(Text, { x: STAMP_PADDING_X, y: STAMP_PADDING_Y + VALUE_FONT_BASELINE_OFFSET, text: valueText, font: valueFont, color: "#111827" })), showLabel && labelFont && (_jsx(Text, { x: STAMP_PADDING_X, y: STAMP_PADDING_Y + LABEL_FONT_BASELINE_OFFSET, text: label, font: labelFont, color: "#6B7280" }))] }));
|
|
30
|
-
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { type SkFont } from '@shopify/react-native-skia';
|
|
2
|
-
import type { AnnotationShape } from '../../types/annotation.js';
|
|
3
|
-
export interface ShapeElementProps {
|
|
4
|
-
shape: AnnotationShape;
|
|
5
|
-
font?: SkFont | null;
|
|
6
|
-
}
|
|
7
|
-
export declare const ShapeElement: ({ shape, font }: ShapeElementProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Circle, Line, Path, Rect, Skia, Text, } from '@shopify/react-native-skia';
|
|
3
|
-
import { useMemo } from 'react';
|
|
4
|
-
const polygonPath = (points) => {
|
|
5
|
-
const path = Skia.Path.Make();
|
|
6
|
-
if (points.length === 0)
|
|
7
|
-
return path;
|
|
8
|
-
path.moveTo(points[0].x, points[0].y);
|
|
9
|
-
for (let i = 1; i < points.length; i++) {
|
|
10
|
-
path.lineTo(points[i].x, points[i].y);
|
|
11
|
-
}
|
|
12
|
-
path.close();
|
|
13
|
-
return path;
|
|
14
|
-
};
|
|
15
|
-
export const ShapeElement = ({ shape, font }) => {
|
|
16
|
-
const { kind, geometry, style, text } = shape;
|
|
17
|
-
const stroke = style.stroke ?? '#000000';
|
|
18
|
-
const fill = style.fill;
|
|
19
|
-
const strokeWidth = style.strokeWidth ?? 2;
|
|
20
|
-
const polyPath = useMemo(() => (kind === 'polygon' ? polygonPath(geometry.points) : null), [kind, geometry.points]);
|
|
21
|
-
switch (kind) {
|
|
22
|
-
case 'rect': {
|
|
23
|
-
const [a, b] = geometry.points;
|
|
24
|
-
if (!a || !b)
|
|
25
|
-
return null;
|
|
26
|
-
const x = Math.min(a.x, b.x);
|
|
27
|
-
const y = Math.min(a.y, b.y);
|
|
28
|
-
const w = Math.abs(b.x - a.x);
|
|
29
|
-
const h = Math.abs(b.y - a.y);
|
|
30
|
-
return (_jsxs(_Fragment, { children: [fill && _jsx(Rect, { x: x, y: y, width: w, height: h, color: fill }), _jsx(Rect, { x: x, y: y, width: w, height: h, color: stroke, style: "stroke", strokeWidth: strokeWidth })] }));
|
|
31
|
-
}
|
|
32
|
-
case 'ellipse': {
|
|
33
|
-
const [a, b] = geometry.points;
|
|
34
|
-
if (!a || !b)
|
|
35
|
-
return null;
|
|
36
|
-
const cx = (a.x + b.x) / 2;
|
|
37
|
-
const cy = (a.y + b.y) / 2;
|
|
38
|
-
const r = Math.max(Math.abs(b.x - a.x), Math.abs(b.y - a.y)) / 2;
|
|
39
|
-
return (_jsxs(_Fragment, { children: [fill && _jsx(Circle, { cx: cx, cy: cy, r: r, color: fill }), _jsx(Circle, { cx: cx, cy: cy, r: r, color: stroke, style: "stroke", strokeWidth: strokeWidth })] }));
|
|
40
|
-
}
|
|
41
|
-
case 'line':
|
|
42
|
-
case 'arrow': {
|
|
43
|
-
const [a, b] = geometry.points;
|
|
44
|
-
if (!a || !b)
|
|
45
|
-
return null;
|
|
46
|
-
return (_jsx(Line, { p1: a, p2: b, color: stroke, style: "stroke", strokeWidth: strokeWidth, strokeCap: "round" }));
|
|
47
|
-
}
|
|
48
|
-
case 'polygon': {
|
|
49
|
-
if (!polyPath)
|
|
50
|
-
return null;
|
|
51
|
-
return (_jsxs(_Fragment, { children: [fill && _jsx(Path, { path: polyPath, color: fill }), _jsx(Path, { path: polyPath, color: stroke, style: "stroke", strokeWidth: strokeWidth })] }));
|
|
52
|
-
}
|
|
53
|
-
case 'text': {
|
|
54
|
-
const [origin] = geometry.points;
|
|
55
|
-
if (!origin || !text)
|
|
56
|
-
return null;
|
|
57
|
-
if (!font)
|
|
58
|
-
return null;
|
|
59
|
-
return (_jsx(Text, { x: origin.x, y: origin.y, text: text, font: font, color: stroke }));
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { type SkPath } from '@shopify/react-native-skia';
|
|
2
|
-
import type { AnnotationStroke } from '../../types/annotation.js';
|
|
3
|
-
export declare const pointsToSkPath: (points: number[]) => SkPath;
|
|
4
|
-
export interface StrokeElementProps {
|
|
5
|
-
stroke: AnnotationStroke;
|
|
6
|
-
}
|
|
7
|
-
export declare const StrokeElement: ({ stroke }: StrokeElementProps) => import("react/jsx-runtime").JSX.Element;
|