@thatopen/services 0.3.10 → 0.3.12
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/cli/commands/revit.d.ts +9 -0
- package/dist/cli/lib/revit-addin.d.ts +20 -0
- package/dist/cli.js +101 -0
- package/dist/cloud/LasToPotree.d.ts +59 -0
- package/dist/cloud/SplatToFq.d.ts +38 -0
- package/dist/cloud/index.d.ts +2 -0
- package/docs/builtin/paths.json +86 -86
- package/docs/cloud/GaussianSplatConverter.md +43 -0
- package/docs/cloud/PointCloudConverter.md +53 -0
- package/docs/revit-collab-quickstart.md +151 -0
- package/package.json +95 -95
- package/src/built-in/ClashesManager/example.ts +283 -283
- package/src/built-in/UIManager/src/clashes-panel/example.ts +160 -160
- package/src/built-in/UIManager/src/models-list/example.ts +122 -118
- package/src/cli/templates/app/README.md +217 -241
- package/src/cli/templates/app/package.json +33 -33
- package/src/cli/templates/app/src/setups/camera-tools.ts +0 -63
- package/src/cli/templates/app/src/setups/camera-views.ts +0 -201
- package/src/cli/templates/app/src/setups/card-header.ts +0 -35
- package/src/cli/templates/app/src/setups/clipper-tool.ts +0 -773
- package/src/cli/templates/app/src/setups/clipper.ts +0 -75
- package/src/cli/templates/app/src/setups/cloud-runner.ts +0 -13
- package/src/cli/templates/app/src/setups/exploded-view.ts +0 -246
- package/src/cli/templates/app/src/setups/helper-panel.ts +0 -88
- package/src/cli/templates/app/src/setups/hider.ts +0 -98
- package/src/cli/templates/app/src/setups/index.ts +0 -23
- package/src/cli/templates/app/src/setups/inspection.ts +0 -136
- package/src/cli/templates/app/src/setups/measurement-panel.ts +0 -188
- package/src/cli/templates/app/src/setups/measurement-tool.ts +0 -588
- package/src/cli/templates/app/src/setups/measurements.ts +0 -133
- package/src/cli/templates/app/src/setups/navigation-gizmo.ts +0 -316
- package/src/cli/templates/app/src/setups/plans-panel.ts +0 -619
- package/src/cli/templates/app/src/setups/right-sidebar.ts +0 -178
- package/src/cli/templates/app/src/setups/styles-panel.ts +0 -110
- package/src/cli/templates/app/src/setups/styles.ts +0 -375
- package/src/cli/templates/app/src/setups/tool-mode-manager.ts +0 -156
- package/src/cli/templates/app/src/setups/tool-mode.ts +0 -23
- package/src/cli/templates/app/src/setups/toolbar.ts +0 -229
- package/src/cli/templates/app/src/setups/ui-manager.ts +0 -27
|
@@ -1,241 +1,217 @@
|
|
|
1
|
-
# ThatOpen BIM App
|
|
2
|
-
|
|
3
|
-
This is a BIM (Building Information Modeling) app built for the That Open Platform.
|
|
4
|
-
It runs in the browser inside the platform's iframe and has access to a 3D viewer,
|
|
5
|
-
UI components, and the platform API.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
##
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
###
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
import
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const response = await
|
|
199
|
-
|
|
200
|
-
await
|
|
201
|
-
|
|
202
|
-
//
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const response = await client.downloadFile(fileId);
|
|
219
|
-
await client.createFile({ file: blob, name: "model.ifc", versionTag: "v1" });
|
|
220
|
-
|
|
221
|
-
// Folders
|
|
222
|
-
const folders = await client.listFolders();
|
|
223
|
-
await client.createFolder("My Folder");
|
|
224
|
-
|
|
225
|
-
// Execute cloud components
|
|
226
|
-
const { executionId } = await client.executeComponent(componentId, { param: "value" });
|
|
227
|
-
client.onExecutionProgress(executionId, (data) => {
|
|
228
|
-
// data.progressUpdate — progress percentage
|
|
229
|
-
// data.messageUpdate — status messages
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
// Test against a local cloud component (requires thatopen local-server running in the component project)
|
|
233
|
-
client.localServerUrl = "http://localhost:4001";
|
|
234
|
-
const local = await client.executeComponent("any-id", { param: "value" });
|
|
235
|
-
client.localServerUrl = null; // reset to use the cloud API
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
## Configuration
|
|
239
|
-
|
|
240
|
-
- `.thatopen` — local config (gitignored). Created by `npm run login`. Contains `accessToken`, `apiUrl`, and `appId` after first publish.
|
|
241
|
-
- `vite.config.js` — builds to IIFE format as `dist/bundle.js`. All dependencies are bundled.
|
|
1
|
+
# ThatOpen BIM App
|
|
2
|
+
|
|
3
|
+
This is a BIM (Building Information Modeling) app built for the That Open Platform.
|
|
4
|
+
It runs in the browser inside the platform's iframe and has access to a 3D viewer,
|
|
5
|
+
UI components, and the platform API.
|
|
6
|
+
|
|
7
|
+
> IMPORTANT for AI assistants: the authoritative, always-current reference for the
|
|
8
|
+
> platform rules, the built-in components, and how to wire each one is shipped
|
|
9
|
+
> inside the installed package. Read these before writing code:
|
|
10
|
+
>
|
|
11
|
+
> - `node_modules/@thatopen/services/resources/AGENTS.md` — platform rules + the
|
|
12
|
+
> full navigation table.
|
|
13
|
+
> - `node_modules/@thatopen/services/docs/builtin/paths.json` — the index of every
|
|
14
|
+
> built-in component, with a one-line description and the path to its example.
|
|
15
|
+
> - `node_modules/@thatopen/services/src/built-in/<Component>/example.ts` — a
|
|
16
|
+
> complete, copy-adaptable integration example per component.
|
|
17
|
+
>
|
|
18
|
+
> This README explains the app's shape and the general pattern. For the exact API
|
|
19
|
+
> of any built-in, trust `paths.json` + the example files over any list here.
|
|
20
|
+
|
|
21
|
+
## How this app works
|
|
22
|
+
|
|
23
|
+
- **Entry point**: `src/main.ts` — runs as an IIFE when the platform loads the app.
|
|
24
|
+
- **Build output**: `dist/bundle.js` — a single IIFE file.
|
|
25
|
+
- **Platform context**: the platform injects the app's context (project id, access
|
|
26
|
+
token, API url). `PlatformClient.fromPlatformContext()` reads it for you.
|
|
27
|
+
|
|
28
|
+
## Commands
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm run dev # Start the dev server (esbuild watch + serve on :4000)
|
|
32
|
+
npm run build # Build dist/bundle.js
|
|
33
|
+
npm run login # Authenticate with the platform (saves token locally)
|
|
34
|
+
npm run publish # Publish to the platform
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Local development
|
|
38
|
+
|
|
39
|
+
Apps run inside the That Open Platform within a project, not as standalone websites.
|
|
40
|
+
To develop locally:
|
|
41
|
+
|
|
42
|
+
1. Run `npm run dev` — watches source with esbuild and serves the bundle on port 4000.
|
|
43
|
+
2. Open your project on the platform and click the debug button.
|
|
44
|
+
3. Live reload is enabled — save a file to rebuild automatically.
|
|
45
|
+
|
|
46
|
+
**Important**: use `npm run dev` (it runs `thatopen serve` under the hood). Do NOT run
|
|
47
|
+
`vite` / `vite build --watch` directly for development — `thatopen serve` applies the
|
|
48
|
+
correct build settings (including the beta engine-library aliases for beta projects).
|
|
49
|
+
|
|
50
|
+
## Key libraries
|
|
51
|
+
|
|
52
|
+
| Package | Import as | Purpose |
|
|
53
|
+
|---------|-----------|---------|
|
|
54
|
+
| `@thatopen/components` | `OBC` | BIM engine — components, fragments, worlds |
|
|
55
|
+
| `@thatopen/components-front` | `OBF` | Front-end BIM components (Highlighter, measurements, …) |
|
|
56
|
+
| `@thatopen/fragments` | `FRAGS` | Fragment geometry format |
|
|
57
|
+
| `@thatopen/ui` | `BUI` | UI web components (`<bim-panel>`, `<bim-grid>`, …) |
|
|
58
|
+
| `three` | `THREE` | 3D rendering engine |
|
|
59
|
+
| `@markerjs/markerjs3` | `MARKERJS` | Screenshot annotation |
|
|
60
|
+
| `@thatopen/services` | (named exports) | Platform API client (`PlatformClient`) + built-in components |
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import * as OBC from "@thatopen/components";
|
|
64
|
+
import * as OBF from "@thatopen/components-front";
|
|
65
|
+
import * as FRAGS from "@thatopen/fragments";
|
|
66
|
+
import * as BUI from "@thatopen/ui";
|
|
67
|
+
import * as THREE from "three";
|
|
68
|
+
import * as MARKERJS from "@markerjs/markerjs3";
|
|
69
|
+
import { PlatformClient, UIManager } from "@thatopen/services";
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Architecture
|
|
73
|
+
|
|
74
|
+
The app boots on the **`UIManager`** built-in. `UIManager` registers the platform's
|
|
75
|
+
web components — the app shell and viewport plus every panel — as custom elements you
|
|
76
|
+
place with plain HTML/`BUI.html`:
|
|
77
|
+
|
|
78
|
+
- `<top-app>` — the app shell: a CSS-grid layout system with a sidebar (activity bar)
|
|
79
|
+
for switching named layouts.
|
|
80
|
+
- `<top-viewer>` — the 3D viewport (pre-configured world: scene, camera, renderer,
|
|
81
|
+
fragments), with its own tools baked in.
|
|
82
|
+
- `<top-viewer-toolbar>` — the bottom viewer toolbar (visibility/inspect, clip, measure).
|
|
83
|
+
- Side panels — `<top-model-tree>`, `<top-properties-panel>`, `<top-models-list>`,
|
|
84
|
+
`<top-data-table-panel>`, `<top-objects-panel>`, `<top-settings-panel>`, … — each
|
|
85
|
+
self-wires from the contexts `<top-app>` provides (no `components` plumbing needed).
|
|
86
|
+
|
|
87
|
+
The scaffolded `src/main.ts` already sets this up. The shape is:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const client = PlatformClient.fromPlatformContext();
|
|
91
|
+
|
|
92
|
+
// 1. Register the platform web components. UIManager MUST be in setup — it
|
|
93
|
+
// defines <top-app>, <top-viewer>, the panels, etc. before the DOM renders.
|
|
94
|
+
const { components } = await client.setup<OBC.Components>(
|
|
95
|
+
{ OBC, OBF, BUI, THREE, FRAGS, MARKERJS },
|
|
96
|
+
{ uuid: UIManager.uuid },
|
|
97
|
+
);
|
|
98
|
+
components.get(UIManager).init();
|
|
99
|
+
|
|
100
|
+
// 2. Build the shell: <top-app> with named element slots + named layouts.
|
|
101
|
+
const app = document.createElement("top-app") as any;
|
|
102
|
+
app.elements = {
|
|
103
|
+
viewer: () => BUI.html`<top-viewer></top-viewer>`,
|
|
104
|
+
tree: () => BUI.html`<top-model-tree></top-model-tree>`,
|
|
105
|
+
// …more panels…
|
|
106
|
+
};
|
|
107
|
+
app.layouts = {
|
|
108
|
+
Explorer: { icon: "mdi:file-tree", template: `"tree viewer" 1fr / 22rem 1fr` },
|
|
109
|
+
// …more layouts…
|
|
110
|
+
};
|
|
111
|
+
app.layout = "Explorer";
|
|
112
|
+
app.sidebar = true;
|
|
113
|
+
document.getElementById("that-open-app")?.appendChild(app);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
A layout `template` is CSS `grid-template` shorthand: `"areas" rows / columns`, where
|
|
117
|
+
each area name maps to a key in `app.elements`. Each layout with an `icon` becomes a
|
|
118
|
+
sidebar (activity-bar) button.
|
|
119
|
+
|
|
120
|
+
Built-ins are loaded from the platform at runtime **by uuid** through the `setup`
|
|
121
|
+
call. You import each one as a named export from `@thatopen/services` (a ready
|
|
122
|
+
`{ uuid }` stub with types), never by a deep/internal path.
|
|
123
|
+
|
|
124
|
+
## Built-in components
|
|
125
|
+
|
|
126
|
+
The current, authoritative list lives in
|
|
127
|
+
`node_modules/@thatopen/services/docs/builtin/paths.json` (index) with a full example
|
|
128
|
+
per component under `node_modules/@thatopen/services/src/built-in/`. At a high level:
|
|
129
|
+
|
|
130
|
+
- **`UIManager`** — the shell + viewport + all `top-*` panels above (already wired by
|
|
131
|
+
the scaffold).
|
|
132
|
+
- **`CDEManager`** — the platform CDE: files, folders, versions, metadata.
|
|
133
|
+
- **`ClashesManager`** + `<top-clashes-panel>` — clash detection and the ready-made
|
|
134
|
+
clash review UI (detection matrix, run controls, status filters, markers, highlights).
|
|
135
|
+
- **`FileList`** — a simple file list.
|
|
136
|
+
|
|
137
|
+
Read the matching `example.ts` for each before using it — the examples are the
|
|
138
|
+
source of truth for imports, ordering constraints, and wiring.
|
|
139
|
+
|
|
140
|
+
### Adding a built-in feature (the general pattern)
|
|
141
|
+
|
|
142
|
+
Every manager-style built-in follows the same three steps. Example — adding clash
|
|
143
|
+
detection (see `ClashesManager/example.ts` and `UIManager/src/clashes-panel/example.ts`):
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
// 1. Import the built-in as a named export from @thatopen/services.
|
|
147
|
+
import { PlatformClient, UIManager, ClashesManager } from "@thatopen/services";
|
|
148
|
+
|
|
149
|
+
// 2. Register it by uuid in the SAME setup call as UIManager.
|
|
150
|
+
const { components } = await client.setup<OBC.Components>(
|
|
151
|
+
{ OBC, OBF, BUI, THREE, FRAGS, MARKERJS },
|
|
152
|
+
{ uuid: UIManager.uuid },
|
|
153
|
+
{ uuid: ClashesManager.uuid },
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// 3a. Init the manager. Do this BEFORE its panel mounts — the panel reads its
|
|
157
|
+
// initial data in connectedCallback and only subscribes to changes afterward.
|
|
158
|
+
await components.get(ClashesManager).init(client);
|
|
159
|
+
|
|
160
|
+
// 3b. Mount the panel web component in a layout slot (UIManager registered it).
|
|
161
|
+
app.elements = {
|
|
162
|
+
// …existing elements…
|
|
163
|
+
clashes: () => BUI.html`<top-clashes-panel></top-clashes-panel>`,
|
|
164
|
+
};
|
|
165
|
+
app.layouts = {
|
|
166
|
+
// …existing layouts…
|
|
167
|
+
Clashes: { icon: "mdi:vector-intersection", template: `"clashes viewer" 1fr / 22rem 1fr` },
|
|
168
|
+
};
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The panel self-wires to its manager — you do not pass props or wire events by hand.
|
|
172
|
+
|
|
173
|
+
## Loading a BIM model
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
const fragments = components.get(OBC.FragmentsManager);
|
|
177
|
+
|
|
178
|
+
// From URL
|
|
179
|
+
const buffer = await (await fetch("https://example.com/model.frag")).arrayBuffer();
|
|
180
|
+
await fragments.core.load(buffer, { modelId: "my-model" });
|
|
181
|
+
|
|
182
|
+
// From platform storage
|
|
183
|
+
const fileBuffer = await (await client.downloadFile(fileId)).arrayBuffer();
|
|
184
|
+
await fragments.core.load(fileBuffer, { modelId: "my-model" });
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
(The scaffold's `<top-models-list>` panel already loads models the user picks, so you
|
|
188
|
+
usually don't need to do this by hand.)
|
|
189
|
+
|
|
190
|
+
## PlatformClient API (commonly used in apps)
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
const client = PlatformClient.fromPlatformContext();
|
|
194
|
+
console.log(client.context.projectId);
|
|
195
|
+
|
|
196
|
+
// Files / folders
|
|
197
|
+
const files = await client.listFiles();
|
|
198
|
+
const response = await client.downloadFile(fileId);
|
|
199
|
+
await client.createFile({ file: blob, name: "model.ifc", versionTag: "v1" });
|
|
200
|
+
await client.createFolder("My Folder");
|
|
201
|
+
|
|
202
|
+
// Execute cloud components
|
|
203
|
+
const { executionId } = await client.executeComponent(componentId, { param: "value" });
|
|
204
|
+
client.onExecutionProgress(executionId, (data) => {
|
|
205
|
+
// data.progressUpdate — progress %, data.messageUpdate — status
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Test against a local cloud component (thatopen local-server running in that project)
|
|
209
|
+
client.localServerUrl = "http://localhost:4001";
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Configuration
|
|
213
|
+
|
|
214
|
+
- `.thatopen` — local config (gitignored). Created by `npm run login`; also holds
|
|
215
|
+
`beta: true` for beta projects and the `appId` after the first publish.
|
|
216
|
+
- `vite.config.js` — builds the IIFE `dist/bundle.js`; for beta projects it aliases
|
|
217
|
+
the `@thatopen/*` engine imports to their `@thatopen-platform/*-beta` packages.
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{PROJECT_NAME}}",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"dev": "thatopen serve",
|
|
7
|
-
"build": "vite build",
|
|
8
|
-
"login": "thatopen login --local",
|
|
9
|
-
"publish": "thatopen publish"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@lit/context": "^1.1.6",
|
|
13
|
-
"lit": "^3.0.0",
|
|
14
|
-
"@markerjs/markerjs3": "^3.9.0",
|
|
15
|
-
"@thatopen/components": "~3.4.0",
|
|
16
|
-
"@thatopen/components-front": "~3.4.0",
|
|
17
|
-
"@thatopen/fragments": "~3.4.0",
|
|
18
|
-
"@thatopen/services": "file:../../../..",
|
|
19
|
-
"@thatopen/ui": "~3.4.
|
|
20
|
-
"three": "0.185.0",
|
|
21
|
-
"@sparkjsdev/spark": "^0.1.10",
|
|
22
|
-
"3d-tiles-renderer": "^0.4.28",
|
|
23
|
-
"camera-controls": "^3.1.2",
|
|
24
|
-
"opentype.js": "1.3.4",
|
|
25
|
-
"potree-core": "^2.0.15",
|
|
26
|
-
"web-ifc": "^0.0.77"
|
|
27
|
-
},
|
|
28
|
-
"devDependencies": {
|
|
29
|
-
"@types/three": "^0.182.0",
|
|
30
|
-
"typescript": "^5.2.0",
|
|
31
|
-
"vite": "^5.2.0"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "thatopen serve",
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"login": "thatopen login --local",
|
|
9
|
+
"publish": "thatopen publish"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@lit/context": "^1.1.6",
|
|
13
|
+
"lit": "^3.0.0",
|
|
14
|
+
"@markerjs/markerjs3": "^3.9.0",
|
|
15
|
+
"@thatopen/components": "~3.4.0",
|
|
16
|
+
"@thatopen/components-front": "~3.4.0",
|
|
17
|
+
"@thatopen/fragments": "~3.4.0",
|
|
18
|
+
"@thatopen/services": "file:../../../..",
|
|
19
|
+
"@thatopen/ui": "~3.4.0",
|
|
20
|
+
"three": "0.185.0",
|
|
21
|
+
"@sparkjsdev/spark": "^0.1.10",
|
|
22
|
+
"3d-tiles-renderer": "^0.4.28",
|
|
23
|
+
"camera-controls": "^3.1.2",
|
|
24
|
+
"opentype.js": "1.3.4",
|
|
25
|
+
"potree-core": "^2.0.15",
|
|
26
|
+
"web-ifc": "^0.0.77"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/three": "^0.182.0",
|
|
30
|
+
"typescript": "^5.2.0",
|
|
31
|
+
"vite": "^5.2.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import * as THREE from "three";
|
|
2
|
-
import * as OBC from "@thatopen/components";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Camera tools for the viewer toolbar. Returns controllers matching the
|
|
6
|
-
* toolbar's integration contract:
|
|
7
|
-
* - `fitAll` — ACTION: fit the camera to the whole loaded model.
|
|
8
|
-
* - `orthoToggle` — TOGGLE: switch the projection Perspective ⇄ Orthographic.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
-
const firstWorld = (components: OBC.Components): any =>
|
|
13
|
-
[...components.get(OBC.Worlds).list.values()][0];
|
|
14
|
-
|
|
15
|
-
export interface CameraTools {
|
|
16
|
-
fitAll: { label: string; icon: string; run(): Promise<void> };
|
|
17
|
-
orthoToggle: {
|
|
18
|
-
label: string;
|
|
19
|
-
icon: string;
|
|
20
|
-
active(): boolean;
|
|
21
|
-
activate(): Promise<void>;
|
|
22
|
-
deactivate(): Promise<void>;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const cameraTools = (components: OBC.Components): CameraTools => {
|
|
27
|
-
const fragments = components.get(OBC.FragmentsManager);
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
fitAll: {
|
|
31
|
-
label: "Zoom to fit",
|
|
32
|
-
icon: "mdi:fit-to-page-outline",
|
|
33
|
-
async run() {
|
|
34
|
-
const controls = firstWorld(components)?.camera?.controls;
|
|
35
|
-
if (!controls) return;
|
|
36
|
-
// Union every loaded model's bounding box, then frame its sphere —
|
|
37
|
-
// fitToSphere preserves the current view direction (no rotation snap).
|
|
38
|
-
const box = new THREE.Box3();
|
|
39
|
-
for (const model of fragments.list.values()) {
|
|
40
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
|
-
const b = (model as any).box as THREE.Box3 | undefined;
|
|
42
|
-
if (b && !b.isEmpty()) box.union(b);
|
|
43
|
-
}
|
|
44
|
-
if (box.isEmpty()) return;
|
|
45
|
-
const sphere = box.getBoundingSphere(new THREE.Sphere());
|
|
46
|
-
await controls.fitToSphere(sphere, true);
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
orthoToggle: {
|
|
50
|
-
label: "Orthographic",
|
|
51
|
-
icon: "mdi:angle-right",
|
|
52
|
-
active() {
|
|
53
|
-
return firstWorld(components)?.camera?.projection?.current === "Orthographic";
|
|
54
|
-
},
|
|
55
|
-
async activate() {
|
|
56
|
-
await firstWorld(components)?.camera?.projection?.set?.("Orthographic");
|
|
57
|
-
},
|
|
58
|
-
async deactivate() {
|
|
59
|
-
await firstWorld(components)?.camera?.projection?.set?.("Perspective");
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
};
|