@toolpath/viewer 1.4.0 → 1.5.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/README.md +287 -55
- package/dist/assets/banana.glb +0 -0
- package/dist/{chunk-HH3W5T42.js → chunk-4TBLMR4Z.js} +727 -168
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/index.d.ts +205 -19
- package/dist/index.js +739 -409
- package/dist/{normalize-DHOSNiuO.d.ts → normalize-CvnV9Ggh.d.ts} +55 -18
- package/dist/toolbar.css +108 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -76,6 +76,7 @@ What each wrapper is for:
|
|
|
76
76
|
├─ <EnginePart> validates the report, loads the mesh, then renders <PartMesh>
|
|
77
77
|
│ └─ <PartMesh> draws the part and handles hover, click, colours, section cuts
|
|
78
78
|
├─ <DirectionArrows> arrows for the directions the part can be machined from
|
|
79
|
+
├─ <Stock> <BoxStock> translucent stock, included when fitting the camera
|
|
79
80
|
├─ <SectionTool> optional: click a face or a plane to cut the part open
|
|
80
81
|
├─ <MeasureTool> optional: click two points for a distance, three for an angle
|
|
81
82
|
├─ <Grid> <Axes> reference geometry, sized to the part
|
|
@@ -95,6 +96,16 @@ What each wrapper is for:
|
|
|
95
96
|
4. **You own the state.** The viewer tells you what was clicked (`onPick`), and you tell it what to
|
|
96
97
|
highlight (`selection`, `highlights`, …). It never changes your selection by itself.
|
|
97
98
|
|
|
99
|
+
### Focus the current selection
|
|
100
|
+
|
|
101
|
+
Pass `focus` to make selected features solid while the remainder of the part becomes translucent.
|
|
102
|
+
The default outside opacity is 15%; set `opacity` for a different X-ray strength. With no selected
|
|
103
|
+
features, the part stays fully opaque.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
<EnginePart report={report} selection={selection} focus={{ opacity: 0.12 }} />
|
|
107
|
+
```
|
|
108
|
+
|
|
98
109
|
Parts are in **millimetres** with **Z pointing up**. The camera uses the same convention.
|
|
99
110
|
|
|
100
111
|
### A click usually matches several features
|
|
@@ -103,23 +114,221 @@ The same face is usually owned by **5–8 features at once**, even on a plain cu
|
|
|
103
114
|
`face` when cut from one direction, a `wall` when cut from another, and part of every `profile`
|
|
104
115
|
around it. So a click gives you every match, and you decide which to use:
|
|
105
116
|
|
|
106
|
-
| Field | What it contains
|
|
107
|
-
| ---------------- |
|
|
108
|
-
| `pick.best` | The most likely feature, or `null`
|
|
109
|
-
| `pick.ranked` | Every matching feature, most likely first
|
|
110
|
-
| `pick.owners` | Every matching feature, in report order
|
|
111
|
-
| `pick.region` | The index of the face that was clicked
|
|
112
|
-
| `pick.point` | Where the click hit, as `[x, y, z]`
|
|
113
|
-
| `pick.normal` | The direction the clicked surface faces, as `[x, y, z]`
|
|
114
|
-
| `pick.
|
|
115
|
-
| `pick.
|
|
117
|
+
| Field | What it contains |
|
|
118
|
+
| ---------------- | --------------------------------------------------------------------- |
|
|
119
|
+
| `pick.best` | The most likely feature, or `null` |
|
|
120
|
+
| `pick.ranked` | Every matching feature, most likely first |
|
|
121
|
+
| `pick.owners` | Every matching feature, in report order |
|
|
122
|
+
| `pick.region` | The index of the face that was clicked |
|
|
123
|
+
| `pick.point` | Where the click hit, as `[x, y, z]` |
|
|
124
|
+
| `pick.normal` | The direction the clicked surface faces, as `[x, y, z]` |
|
|
125
|
+
| `pick.pointer` | Browser coordinates for an application-owned hover card, when present |
|
|
126
|
+
| `pick.modifiers` | `{ alt, ctrl, meta, shift, secondary }`: keys held, and right-click |
|
|
127
|
+
| `pick.doubled` | `true` if this click was the second half of a double-click |
|
|
116
128
|
|
|
117
129
|
The ranking puts specific features first: holes, then pockets and bosses, then chamfers and
|
|
118
130
|
fillets, then walls and faces, then profiles. Among features of the same kind, the one whose
|
|
119
131
|
machining direction points most toward the camera wins.
|
|
120
132
|
|
|
133
|
+
`onHover` receives the same `PartPick` shape. Use the optional `pointer` location yourself, or
|
|
134
|
+
wrap application content in `<HoverCard pick={hoverPick}>`; it follows the cursor while that
|
|
135
|
+
region remains hovered. The viewer intentionally leaves card content and actions to the application.
|
|
136
|
+
Hover feedback is on by default; pass `hover={false}` to disable both face feedback and `onHover`
|
|
137
|
+
callbacks while preserving clicks. That makes an application toolbar's feature-hover toggle
|
|
138
|
+
unambiguous.
|
|
139
|
+
|
|
140
|
+
The normalized model contains feature identity, type, directions, face shape, and analytic area.
|
|
141
|
+
An Engine DFM card can join `pick.best` to the part's detailed feature data and render its own
|
|
142
|
+
depth, clearance-diameter, or L/D rows inside `HoverCard`; setup labels remain application or plan
|
|
143
|
+
context rather than a fact of the part surface.
|
|
144
|
+
|
|
121
145
|
## Components
|
|
122
146
|
|
|
147
|
+
### Stock and display controls
|
|
148
|
+
|
|
149
|
+
Use `<BoxStock>` for an axis-aligned blank around a part, or `<Stock geometry={stockGeometry} />`
|
|
150
|
+
for an actual stock mesh, including cylindrical or irregular blanks. Stock and part coordinates
|
|
151
|
+
must use the same millimetre, Z-up frame. Both components include stock in Fit and Reset while
|
|
152
|
+
keeping section tools, measurements, the grid, and direction arrows sized to the finished part.
|
|
153
|
+
Stock does not intercept clicks or get clipped by the part's section plane.
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { useMemo, useRef, useState } from 'react'
|
|
157
|
+
import {
|
|
158
|
+
Axes,
|
|
159
|
+
BoxStock,
|
|
160
|
+
DirectionArrows,
|
|
161
|
+
PartMesh,
|
|
162
|
+
Viewer,
|
|
163
|
+
directionHighlights,
|
|
164
|
+
} from '@toolpath/viewer'
|
|
165
|
+
import type { PartModel, ViewerHandle } from '@toolpath/viewer'
|
|
166
|
+
import type { BufferGeometry } from 'three'
|
|
167
|
+
|
|
168
|
+
export function StockPreview({ model, geometry }: { model: PartModel; geometry: BufferGeometry }) {
|
|
169
|
+
const viewer = useRef<ViewerHandle>(null)
|
|
170
|
+
const [stock, setStock] = useState(false)
|
|
171
|
+
const [axes, setAxes] = useState(true)
|
|
172
|
+
const [directions, setDirections] = useState(false)
|
|
173
|
+
const [direction, setDirection] = useState<number | null>(null)
|
|
174
|
+
const [wireframe, setWireframe] = useState(false)
|
|
175
|
+
const colors = useMemo(
|
|
176
|
+
() => (directions ? directionHighlights(model, direction) : []),
|
|
177
|
+
[model, direction, directions],
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<>
|
|
182
|
+
<Viewer ref={viewer} style={{ height: 500 }}>
|
|
183
|
+
<PartMesh
|
|
184
|
+
model={model}
|
|
185
|
+
geometry={geometry}
|
|
186
|
+
display={wireframe ? 'wireframe' : 'solid'}
|
|
187
|
+
regionHighlights={colors}
|
|
188
|
+
activeDirection={directions ? direction : null}
|
|
189
|
+
/>
|
|
190
|
+
{stock && <BoxStock partGeometry={geometry} allowance={{ wall: 3, floor: 3 }} />}
|
|
191
|
+
{axes && <Axes />}
|
|
192
|
+
<DirectionArrows
|
|
193
|
+
directions={model.candidateDirections}
|
|
194
|
+
visible={directions}
|
|
195
|
+
shownDirection={direction}
|
|
196
|
+
onPickDirection={(index) => setDirection((held) => (held === index ? null : index))}
|
|
197
|
+
/>
|
|
198
|
+
</Viewer>
|
|
199
|
+
<button aria-pressed={stock} onClick={() => setStock(!stock)}>
|
|
200
|
+
Stock
|
|
201
|
+
</button>
|
|
202
|
+
<button aria-pressed={axes} onClick={() => setAxes(!axes)}>
|
|
203
|
+
Axes
|
|
204
|
+
</button>
|
|
205
|
+
<button aria-pressed={directions} onClick={() => setDirections(!directions)}>
|
|
206
|
+
By direction
|
|
207
|
+
</button>
|
|
208
|
+
<button aria-pressed={wireframe} onClick={() => setWireframe(!wireframe)}>
|
|
209
|
+
Wireframe
|
|
210
|
+
</button>
|
|
211
|
+
<button onClick={() => viewer.current?.fit()}>Fit</button>
|
|
212
|
+
</>
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`BoxStock.allowance` is padding **per side**, in millimetres. The preferred form is
|
|
218
|
+
`{ wall, floor }`: wall stock expands X/Y and floor stock expands Z, matching the wall/floor
|
|
219
|
+
roughing-stock distinction used by machining settings. A number or `{ x, y, z }` remains accepted
|
|
220
|
+
for uniform or axis-specific padding. It defaults to zero. `offset` translates the stock from the
|
|
221
|
+
part's bounding-box centre. `boxStockBounds(geometry, allowance, offset)` returns the same `Box3`
|
|
222
|
+
for displaying dimensions.
|
|
223
|
+
|
|
224
|
+
For fixed-box stock, pass `dimensions={{ x, y, z }}` instead. `position` accepts
|
|
225
|
+
`model_centered`, `offset_from_top`, or `offset_from_bottom`, and `positionOffset` is the distance
|
|
226
|
+
from the selected top or bottom bound. All fixed-box values use millimetres and the part's Z-up
|
|
227
|
+
coordinate frame.
|
|
228
|
+
Negative/non-finite allowances, non-finite coordinates, and empty or non-positive stock dimensions
|
|
229
|
+
throw `RangeError`. The 3 mm allowance above is an example, not an automatic stock recommendation.
|
|
230
|
+
|
|
231
|
+
`Stock` accepts `color`, `opacity` (default `0.2`), `edgeColor`, `edgeOpacity`, and `showEdges`.
|
|
232
|
+
`BoxStock` accepts the same appearance props. Caller-provided geometry is never disposed; the
|
|
233
|
+
components dispose their own materials and outlines. Conditionally mount stock to toggle it.
|
|
234
|
+
Toggling stock preserves the camera; Fit/Reset then frames the visible stock together with the part.
|
|
235
|
+
|
|
236
|
+
`directionHighlights(model, activeDirection?)` returns region colors in the same palette as
|
|
237
|
+
`DirectionArrows`. For a face with several owners, the most specific feature wins, followed by
|
|
238
|
+
candidate-direction order and feature tag. Unmatched directions are left unpainted. Hover and
|
|
239
|
+
selection still paint over this wash. Scoping by direction filters ownership; it does not hide
|
|
240
|
+
the rest of the model or claim that an unpainted face cannot be manufactured.
|
|
241
|
+
|
|
242
|
+
Wireframe keeps the existing semantic edges, including rear edges, and keeps faces available for
|
|
243
|
+
picking, measuring, and section placement. Highlighted faces and section caps remain visible.
|
|
244
|
+
`showEdges` controls solid-mode outlines; wireframe always shows them. The example's bottom toolbar
|
|
245
|
+
makes wireframe and direction coloring mutually exclusive and includes a direction legend and
|
|
246
|
+
contextual Section/Measure controls.
|
|
247
|
+
|
|
248
|
+
### `<ViewerToolbar>`
|
|
249
|
+
|
|
250
|
+
`ViewerToolbar` is a composable, viewer-scoped toolbar for camera, display, section, and measurement
|
|
251
|
+
controls. Import its stylesheet alongside your application stylesheet:
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
import '@toolpath/viewer/toolbar.css'
|
|
255
|
+
import { ViewerToolbar, ViewerToolbarProvider } from '@toolpath/viewer'
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Give `ViewerToolbarProvider` the current values and callbacks from the host app, then place the
|
|
259
|
+
toolbar and viewer inside it. The toolbar owns no application state or behavior: it only reads the
|
|
260
|
+
provider. Omit `children` for every configured control in the standard order, or compose the
|
|
261
|
+
individual buttons to use only the controls and order your application needs.
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
<ViewerToolbarProvider
|
|
265
|
+
controls={{
|
|
266
|
+
stock: { pressed: showStock, onClick: () => setShowStock((shown) => !shown) },
|
|
267
|
+
measure: { pressed: measuring, onClick: toggleMeasuring },
|
|
268
|
+
fit: { onClick: () => viewer.current?.fit() },
|
|
269
|
+
}}
|
|
270
|
+
>
|
|
271
|
+
<ViewerToolbar>
|
|
272
|
+
<ViewerToolbar.Controls>
|
|
273
|
+
<ViewerToolbar.MeasureButton />
|
|
274
|
+
<ViewerToolbar.Divider />
|
|
275
|
+
<ViewerToolbar.StockButton />
|
|
276
|
+
<ViewerToolbar.FitButton />
|
|
277
|
+
</ViewerToolbar.Controls>
|
|
278
|
+
</ViewerToolbar>
|
|
279
|
+
<Viewer ref={viewer}>…</Viewer>
|
|
280
|
+
</ViewerToolbarProvider>
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
`ViewerToolbar.Controls`, `Divider`, and the thirteen `*Button` components are available on
|
|
284
|
+
`ViewerToolbar`: `StockButton`, `AxesButton`, `GridButton`, `BananaButton`, `DirectionsButton`,
|
|
285
|
+
`HoverButton`, `FocusButton`, `WireframeButton`, `SectionButton`, `MeasureButton`, `FitButton`,
|
|
286
|
+
`ResetButton`, and `TopButton`. A rendered button requires its matching provider control. For an
|
|
287
|
+
application-specific toolbar component, `useViewerToolbar()` reads the same controls from inside
|
|
288
|
+
the provider.
|
|
289
|
+
|
|
290
|
+
#### Styling hooks
|
|
291
|
+
|
|
292
|
+
Every viewer, hover-card, and toolbar DOM boundary has a stable class name. Your `className` on
|
|
293
|
+
`<Viewer>`, `<ViewerToolbar>`, or `<HoverCard>` is appended to the component's own class; it never
|
|
294
|
+
replaces the hook. The toolbar stylesheet uses the same names, so import it for the default look or
|
|
295
|
+
override any of these selectors in your application stylesheet.
|
|
296
|
+
|
|
297
|
+
| Component | Class | Element |
|
|
298
|
+
| ----------------- | ------------------------- | --------------------------------- |
|
|
299
|
+
| `<Viewer>` | `viewer-root` | Wrapper around the canvas |
|
|
300
|
+
| `<Viewer>` | `viewer-canvas-container` | R3F canvas event container |
|
|
301
|
+
| `<Viewer>` | `viewer-canvas-frame` | R3F's canvas-sizing frame |
|
|
302
|
+
| `<Viewer>` | `viewer-canvas` | The `<canvas>` itself |
|
|
303
|
+
| `<HoverCard>` | `viewer-hover-card` | Cursor-following tooltip shell |
|
|
304
|
+
| `<ViewerToolbar>` | `viewer-toolbar-stack` | Outer toolbar stack |
|
|
305
|
+
| `<ViewerToolbar>` | `viewer-toolbar` | Controls group |
|
|
306
|
+
| `<ViewerToolbar>` | `viewer-toolbar-button` | Each standard control button |
|
|
307
|
+
| `<ViewerToolbar>` | `viewer-toolbar-icon` | SVG within a standard control |
|
|
308
|
+
| `<ViewerToolbar>` | `viewer-toolbar-tooltip` | Label shown on button hover/focus |
|
|
309
|
+
| `<ViewerToolbar>` | `viewer-toolbar-divider` | Separator between control groups |
|
|
310
|
+
|
|
311
|
+
The following `data-*` attributes identify generated elements without depending on labels, which
|
|
312
|
+
can change with state or localization:
|
|
313
|
+
|
|
314
|
+
| Attribute | Element and values |
|
|
315
|
+
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
316
|
+
| `data-viewer-root="true"` | `<Viewer>` wrapper |
|
|
317
|
+
| `data-viewer-canvas-container="true"` | R3F canvas event container |
|
|
318
|
+
| `data-viewer-canvas-frame="true"` | R3F canvas-sizing frame |
|
|
319
|
+
| `data-viewer-canvas="true"` | The `<canvas>` itself |
|
|
320
|
+
| `data-viewer-hover-card="true"` | `<HoverCard>` shell |
|
|
321
|
+
| `data-viewer-toolbar="true"` | Toolbar stack |
|
|
322
|
+
| `data-viewer-toolbar-controls="true"` | Controls group |
|
|
323
|
+
| `data-viewer-toolbar-action` | Standard button: `stock`, `axes`, `grid`, `banana`, `directions`, `hover`, `focus`, `wireframe`, `section`, `measure`, `fit`, `reset`, or `top` |
|
|
324
|
+
| `data-viewer-toolbar-icon="true"` | Standard button SVG |
|
|
325
|
+
| `data-viewer-toolbar-tooltip="true"` | Standard button tooltip |
|
|
326
|
+
| `data-viewer-toolbar-divider="true"` | Toolbar separator |
|
|
327
|
+
|
|
328
|
+
Toggle buttons also carry standard `aria-pressed="true"` or `"false"`; use that to style their
|
|
329
|
+
current state. `Fit`, `Reset`, and `Top view` are actions rather than toggles, so they omit the
|
|
330
|
+
attribute.
|
|
331
|
+
|
|
123
332
|
### `<Viewer>`
|
|
124
333
|
|
|
125
334
|
The canvas that holds everything. Import it from `@toolpath/viewer`.
|
|
@@ -127,7 +336,7 @@ The canvas that holds everything. Import it from `@toolpath/viewer`.
|
|
|
127
336
|
| Prop | Default | What it does |
|
|
128
337
|
| ----------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
129
338
|
| `projection` | `'orthographic'` | `'orthographic'` keeps parallel lines parallel. `'perspective'` gives depth, which helps with deep pockets. |
|
|
130
|
-
| `controls` | `'toolpath'` |
|
|
339
|
+
| `controls` | `'toolpath'` | CAD navigation preset. See [CAD controls](#cad-controls). |
|
|
131
340
|
| `zoomTo` | `'cursor'` | Zoom toward the pointer, or toward `'centre'` (often easier on a trackpad). |
|
|
132
341
|
| `freeOrbit` | `true` | Let the view keep rotating past straight-up and straight-down. |
|
|
133
342
|
| `retargetOnDoubleClick` | `true` | Double-click the part to rotate around that point. |
|
|
@@ -142,20 +351,35 @@ Changing `projection` rebuilds the canvas and returns the camera to its starting
|
|
|
142
351
|
|
|
143
352
|
The canvas is transparent. To set a background colour, style the wrapper or its parent.
|
|
144
353
|
|
|
145
|
-
####
|
|
354
|
+
#### CAD controls
|
|
355
|
+
|
|
356
|
+
`controls` changes only the navigation gestures. It does not choose a projection: the viewer stays
|
|
357
|
+
orthographic by default, and `projection="perspective"` remains an independent opt-in.
|
|
358
|
+
|
|
359
|
+
| Value | Label | Rotate | Pan | Zoom |
|
|
360
|
+
| -------------- | ---------- | ------------------------------------- | ----------------------------------------- | ----------------------------------- |
|
|
361
|
+
| `'toolpath'` | Toolpath | Left-drag | Right-drag | Scroll wheel |
|
|
362
|
+
| `'fusion'` | Fusion | Shift + middle-drag or Shift + scroll | Middle-drag, scroll, or two-finger scroll | Trackpad pinch |
|
|
363
|
+
| `'alias'` | Alias | Left-drag | Middle-drag | Scroll wheel |
|
|
364
|
+
| `'inventor'` | Inventor | Shift + middle-drag or Shift + scroll | Middle-drag, scroll, or two-finger scroll | Trackpad pinch |
|
|
365
|
+
| `'solidworks'` | SolidWorks | Middle-drag | Ctrl + middle-drag | Shift + middle-drag or scroll wheel |
|
|
366
|
+
| `'tinkercad'` | Tinkercad | Right-drag | Shift + right-drag | Scroll wheel |
|
|
367
|
+
| `'powermill'` | PowerMill | Middle-drag | Shift + middle-drag | Scroll wheel |
|
|
368
|
+
| `'onshape'` | Onshape | Right-drag | Middle-drag | Scroll wheel |
|
|
369
|
+
|
|
370
|
+
Fusion and Inventor treat a two-finger scroll as pan, Shift + two-finger scroll as orbit, and a
|
|
371
|
+
pinch (a wheel event with Ctrl set by the browser) as zoom. Other schemes use one-finger rotate,
|
|
372
|
+
two-finger pinch-and-pan, and three-finger pan on touch screens.
|
|
146
373
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
| Pan | Right-drag or middle-drag | Middle-drag, or scroll / two-finger scroll |
|
|
151
|
-
| Zoom | Scroll wheel | Trackpad pinch |
|
|
152
|
-
| Rotate around a point | Double-click the part | Double-click the part |
|
|
153
|
-
| Fit whole part | Double middle-click | Double middle-click |
|
|
374
|
+
All schemes support double-clicking the part to rotate around that point and double-clicking the
|
|
375
|
+
middle mouse button to fit the whole part. Dragging never selects anything; a click only counts if
|
|
376
|
+
the pointer barely moved.
|
|
154
377
|
|
|
155
|
-
|
|
156
|
-
|
|
378
|
+
The package exports `CONTROL_SCHEME_OPTIONS`, `ControlScheme`, and `ControlSchemeOption` for a host
|
|
379
|
+
application's settings UI. It deliberately stores no preferences: pass the selected `controls`,
|
|
380
|
+
`freeOrbit`, and `zoomTo` values to `<Viewer>` from your own state or persistence layer.
|
|
157
381
|
|
|
158
|
-
|
|
382
|
+
`'toolpath'`, `freeOrbit={true}`, and `zoomTo="cursor"` are the defaults.
|
|
159
383
|
|
|
160
384
|
### `<EnginePart>`
|
|
161
385
|
|
|
@@ -176,28 +400,30 @@ Draws the part and handles clicks. You only use it directly when you
|
|
|
176
400
|
|
|
177
401
|
**Colours**
|
|
178
402
|
|
|
179
|
-
| Prop | Type
|
|
180
|
-
| ------------------- |
|
|
181
|
-
| `selection` | `string[]`
|
|
182
|
-
| `highlights` | `FeatureHighlight[]`
|
|
183
|
-
| `regionHighlights` | `RegionHighlight[]`
|
|
184
|
-
| `candidates` | `string[]`
|
|
185
|
-
| `pickedRegions` | `number[]`
|
|
186
|
-
| `hoveredFeatureIds` | `string[]`
|
|
187
|
-
| `showEdges` | `boolean` (`true`)
|
|
188
|
-
| `
|
|
403
|
+
| Prop | Type | What it does |
|
|
404
|
+
| ------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------- |
|
|
405
|
+
| `selection` | `string[]` | Feature tags to highlight as selected (orange). |
|
|
406
|
+
| `highlights` | `FeatureHighlight[]` | Your own colour per feature, e.g. difficulty or setup. |
|
|
407
|
+
| `regionHighlights` | `RegionHighlight[]` | Your own colour per face. |
|
|
408
|
+
| `candidates` | `string[]` | Other possible matches, faintly tinted by machining direction. |
|
|
409
|
+
| `pickedRegions` | `number[]` | Faces to mark as just clicked. |
|
|
410
|
+
| `hoveredFeatureIds` | `string[]` | Features to show as hovered, e.g. when hovering a list row. |
|
|
411
|
+
| `showEdges` | `boolean` (`true`) | Draw outlines between faces. |
|
|
412
|
+
| `display` | `'solid' \| 'wireframe'` (`'solid'`) | Wireframe draws face boundaries without triangle diagonals. Painted and hovered faces remain visible. |
|
|
413
|
+
| `theme` | `Partial<ViewerTheme>` | Override the part's colours. |
|
|
189
414
|
|
|
190
415
|
**Interaction**
|
|
191
416
|
|
|
192
|
-
| Prop | Type | What it does
|
|
193
|
-
| ----------------- | ---------------------------------- |
|
|
194
|
-
| `onPick` | `(pick: PartPick) => void` | Left- or right-click on the part.
|
|
195
|
-
| `onHover` | `(pick: PartPick \| null) => void` | The pointer moved onto a different face, or off the part (`null`).
|
|
196
|
-
| `
|
|
197
|
-
| `
|
|
198
|
-
| `
|
|
199
|
-
| `
|
|
200
|
-
| `
|
|
417
|
+
| Prop | Type | What it does |
|
|
418
|
+
| ----------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
419
|
+
| `onPick` | `(pick: PartPick) => void` | Left- or right-click on the part. |
|
|
420
|
+
| `onHover` | `(pick: PartPick \| null) => void` | The pointer moved onto a different face, or off the part (`null`). |
|
|
421
|
+
| `hover` | `boolean` (`true`) | Paint and report faces under the pointer. `false` leaves click picking on and clears any hover. |
|
|
422
|
+
| `activeDirection` | `number \| null` | Only match features machined from this direction (an index into `candidateDirections`). |
|
|
423
|
+
| `focusFeature` | `string \| null` | Zoom to this feature. The camera moves each time the value changes. |
|
|
424
|
+
| `section` | `SectionOptions` | Cut the part open. Omit it to follow the viewer's own cut. See [Section view](#section-view). |
|
|
425
|
+
| `onSectionChange` | `(state: SectionState) => void` | Called when the cut moves or goes away. With `section`, passing it also shows the drag handle. |
|
|
426
|
+
| `onAdjacency` | `(map) => void` | Called once per mesh with which faces touch which. |
|
|
201
427
|
|
|
202
428
|
Hovering over the part is handled for you. You only need `onHover` if you want to show the hovered
|
|
203
429
|
feature elsewhere in your UI.
|
|
@@ -478,7 +704,10 @@ no `section` prop:
|
|
|
478
704
|
|
|
479
705
|
Hovering the part previews a cut through the face under the pointer; clicking places it. Three
|
|
480
706
|
coloured planes stand behind the part — click one to cut along that axis, in from your side. Once
|
|
481
|
-
there is a cut,
|
|
707
|
+
there is a cut, a framed plane and two-way normal-axis handle show exactly what will move; drag the
|
|
708
|
+
handle to move it. Keep the canvas clear by presenting `sectionMeasurement(state)` beside the host
|
|
709
|
+
application's section slider; it reports the depth from a picked surface, or the distance swept
|
|
710
|
+
through the part bounds. Escape clears it.
|
|
482
711
|
The cut belongs to the viewer: `viewer.current.setSection(null)` clears it from a button outside
|
|
483
712
|
the canvas, `setSection({ enabled: true, normal, offset })` sets one, and `onSectionChange` on
|
|
484
713
|
`PartMesh` still reports every move.
|
|
@@ -505,7 +734,7 @@ const [offset, setOffset] = useState(0.5)
|
|
|
505
734
|
```
|
|
506
735
|
|
|
507
736
|
The cut surface is filled in with a hatch and outlined, so the part doesn't look hollow and the cut
|
|
508
|
-
reads as a cut. Passing `onSectionChange` also shows
|
|
737
|
+
reads as a cut. Passing `onSectionChange` also shows the draggable plane-frame gizmo. The handler is
|
|
509
738
|
called on every drag and only when the cut actually changes, so it's safe to store the value in
|
|
510
739
|
state; a cut going away is reported once, with `enabled: false`.
|
|
511
740
|
|
|
@@ -625,10 +854,11 @@ go on the cube. See `DEFAULT_THEME` for every key. The default part colours are
|
|
|
625
854
|
default lighting, so if you change one, check the other.
|
|
626
855
|
|
|
627
856
|
The section cut is themed on the part too: `sectionCap` and `sectionHatch` are the cap's fill and
|
|
628
|
-
hatch lines, `sectionHandle` the drag arrow, and `sectionOutline` the
|
|
629
|
-
preview that `<SectionTool>` draws.
|
|
630
|
-
|
|
631
|
-
|
|
857
|
+
hatch lines, `sectionHandle` overrides the drag arrow's colour, and `sectionOutline` the
|
|
858
|
+
cutting-plane sheet and preview that `<SectionTool>` draws. Without a `sectionHandle` override, the
|
|
859
|
+
drag arrow uses the cutting plane's direction colour. `measure` and `measureSnap` are
|
|
860
|
+
`<MeasureTool>`'s lines and its snap indicator; a distance's X, Y, Z legs take `AXIS_COLORS`, the
|
|
861
|
+
same hues as the section tool's global planes.
|
|
632
862
|
|
|
633
863
|
`HIGHLIGHT_COLORS` has the standard selection colours (`default`, `toolIssue`, `geometryIssue`).
|
|
634
864
|
`DIRECTION_COLORS` has the 9 direction colours, which repeat for parts with more than 9 directions.
|
|
@@ -872,12 +1102,13 @@ is a complete app built this way, with no API key needed.
|
|
|
872
1102
|
|
|
873
1103
|
### Hooks
|
|
874
1104
|
|
|
875
|
-
| Hook |
|
|
876
|
-
| --------------------- | -------------------------------------------------------------------------------- |
|
|
877
|
-
| `useViewerControls()` | Get `fit`, `reset`, `setView`, `setViewDirection`, `frameBox`, and `setSection`. |
|
|
878
|
-
| `
|
|
879
|
-
| `
|
|
880
|
-
| `
|
|
1105
|
+
| Hook | Where | What it does |
|
|
1106
|
+
| --------------------- | -------------------------------- | -------------------------------------------------------------------------------- |
|
|
1107
|
+
| `useViewerControls()` | Inside `<Viewer>` | Get `fit`, `reset`, `setView`, `setViewDirection`, `frameBox`, and `setSection`. |
|
|
1108
|
+
| `useViewerToolbar()` | Inside `<ViewerToolbarProvider>` | Get the actions and state supplied to the provider. |
|
|
1109
|
+
| `useSectionStore()` | Inside `<Viewer>` | Read, set, or subscribe to the viewer's own cut. |
|
|
1110
|
+
| `useContentBox()` | Inside `<Viewer>` | Get the part's bounding box (a `THREE.Box3`, empty until loaded). |
|
|
1111
|
+
| `useTapGuard()` | Inside `<Viewer>` | Check whether a pointer event was a click and not a drag. |
|
|
881
1112
|
|
|
882
1113
|
### Helpers
|
|
883
1114
|
|
|
@@ -903,11 +1134,12 @@ use. They're listed in `dist/index.d.ts`.
|
|
|
903
1134
|
|
|
904
1135
|
`ViewerProps`, `ViewerHandle`, `ViewerView`, `Projection`, `ControlScheme`, `EnginePartProps`,
|
|
905
1136
|
`PartMeshProps`, `PartPick`, `PickModifiers`, `PartModel`, `PartModelFeature`, `PartModelRegion`,
|
|
906
|
-
`FeatureTag`, `FeatureType`, `Vec3`, `FeatureHighlight`, `RegionHighlight`, `SectionOptions`,
|
|
1137
|
+
`FeatureTag`, `FeatureType`, `Vec3`, `FeatureHighlight`, `RegionHighlight`, `FocusOptions`, `SectionOptions`,
|
|
907
1138
|
`SectionState`, `SectionPlacement`, `SectionToolProps`, `SectionStore`, `MeasureToolProps`,
|
|
908
1139
|
`MeasureMode`, `Measurement`, `DistanceMeasurement`, `AngleMeasurement`, `Snap`, `SnapKind`,
|
|
909
1140
|
`ViewerTheme`, `ViewName`, `DirectionArrowsProps`, `NamedDirection`, `GridProps`, `AxesProps`,
|
|
910
|
-
`ViewCubeProps
|
|
1141
|
+
`ViewCubeProps`, `ViewerToolbarProps`, `ViewerToolbarControlsProps`, `ViewerToolbarControls`,
|
|
1142
|
+
`ViewerToolbarControl`.
|
|
911
1143
|
|
|
912
1144
|
`FeatureType` and `ShapeKind` accept any string, because newer Engine versions add new values.
|
|
913
1145
|
Handle values you don't recognize.
|
|
Binary file
|