@wemap/viewer 0.0.0-stage → 14.8.0-beta.4
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/LICENSE +23 -0
- package/README.md +189 -2
- package/dist/cdn/wemap-viewer.css +2 -0
- package/dist/cdn/wemap-viewer.umd.js +3676 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11565 -0
- package/dist/src/WemapViewer.d.ts +149 -0
- package/dist/src/WemapViewer.d.ts.map +1 -0
- package/dist/src/controls/SphereControls.d.ts +63 -0
- package/dist/src/controls/SphereControls.d.ts.map +1 -0
- package/dist/src/data/ViewerDataClient.d.ts +31 -0
- package/dist/src/data/ViewerDataClient.d.ts.map +1 -0
- package/dist/src/frame/SceneFrame.d.ts +39 -0
- package/dist/src/frame/SceneFrame.d.ts.map +1 -0
- package/dist/src/graph/MeasureOverlay.d.ts +19 -0
- package/dist/src/graph/MeasureOverlay.d.ts.map +1 -0
- package/dist/src/graph/PanoramaPointer.d.ts +59 -0
- package/dist/src/graph/PanoramaPointer.d.ts.map +1 -0
- package/dist/src/graph/PolygonOverlay.d.ts +22 -0
- package/dist/src/graph/PolygonOverlay.d.ts.map +1 -0
- package/dist/src/transition/PanoramaTransition.d.ts +50 -0
- package/dist/src/transition/PanoramaTransition.d.ts.map +1 -0
- package/dist/src/tweens.d.ts +11 -0
- package/dist/src/tweens.d.ts.map +1 -0
- package/dist/src/types/index.d.ts +147 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/style.css +2 -0
- package/package.json +51 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (c) 2026 Wemap SAS. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and its associated source code, documentation, and other
|
|
4
|
+
materials (the "Software") are the proprietary and confidential property of
|
|
5
|
+
Wemap SAS. The Software is licensed, not sold.
|
|
6
|
+
|
|
7
|
+
No part of the Software may be used, copied, reproduced, modified, merged,
|
|
8
|
+
published, distributed, sublicensed, or sold, in whole or in part, in any form
|
|
9
|
+
or by any means, without the prior written permission of Wemap SAS, except as
|
|
10
|
+
expressly permitted under a separate written license or subscription agreement
|
|
11
|
+
with Wemap SAS. Use of the Software is governed by, and subject to the terms
|
|
12
|
+
of, that agreement.
|
|
13
|
+
|
|
14
|
+
Unauthorized use, reproduction, or distribution of the Software, or any portion
|
|
15
|
+
of it, may result in severe civil and criminal penalties, and will be
|
|
16
|
+
prosecuted to the maximum extent possible under the law.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL WEMAP
|
|
21
|
+
SAS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
23
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,190 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @wemap/viewer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Framework-agnostic **360° panorama viewer** for Wemap maps. It loads the
|
|
4
|
+
map's image graph (the 360° photos captured on site) and lets users look
|
|
5
|
+
around and walk from photo to photo. Built on three.js, with no UI framework.
|
|
6
|
+
|
|
7
|
+
Pair it with [`@wemap/viewer-map`](../viewer-map) to show the graph and the look
|
|
8
|
+
direction on a [`@wemap/map`](../map).
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @wemap/core @wemap/geo @wemap/viewer
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`three` and `@tweenjs/tween.js` are regular dependencies — nothing else to install.
|
|
17
|
+
|
|
18
|
+
### No build step (`<script>` tag)
|
|
19
|
+
|
|
20
|
+
Load the UMD bundle `dist/cdn/wemap-viewer.umd.js` after the `@wemap/core` and
|
|
21
|
+
`@wemap/geo` bundles. It inlines three.js and exposes
|
|
22
|
+
`window.Wemap.Viewer`.
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
- **`core.init()` first.** Identity (emmid), auth and the VPS endpoint all come
|
|
27
|
+
from `@wemap/core`; the viewer takes none of them.
|
|
28
|
+
- **A map with a VPS provider.** Without it, `open()` rejects.
|
|
29
|
+
- **A sized container.** The canvas fills its container and follows its size
|
|
30
|
+
(a `ResizeObserver` handles resizes), so give the container a height.
|
|
31
|
+
|
|
32
|
+
## Quick start
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { core } from '@wemap/core';
|
|
36
|
+
import { WemapViewer } from '@wemap/viewer';
|
|
37
|
+
import '@wemap/viewer/style.css';
|
|
38
|
+
|
|
39
|
+
await core.init({ emmid: '31668', token: '<token>' });
|
|
40
|
+
|
|
41
|
+
const viewer = new WemapViewer(document.getElementById('viewer')!, {
|
|
42
|
+
onNavigate: (nodeId) => console.log('now at', nodeId),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Open on a node, looking east. Resolves once its image is on screen.
|
|
46
|
+
await viewer.open(1059484, { heading: 90 });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`open()` takes a node id (a deep link, a click on the map graph) or a position,
|
|
50
|
+
in which case it opens on the nearest node, on the position's level when it has
|
|
51
|
+
one:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { Coordinates } from '@wemap/geo';
|
|
55
|
+
|
|
56
|
+
// Latitude, longitude, altitude (none), level 1.
|
|
57
|
+
await viewer.open(new Coordinates(43.60907, 3.91719, null, 1));
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The first call fetches the image graph. Later calls move there like
|
|
61
|
+
`navigateTo`, and `heading` turns the view with an animation. Without `heading`
|
|
62
|
+
the look direction is kept. Awaiting is optional: `ready` and `onError` report
|
|
63
|
+
the same outcome.
|
|
64
|
+
|
|
65
|
+
## Moving around
|
|
66
|
+
|
|
67
|
+
- **Look around** by dragging (with inertia), or with the arrow keys once the
|
|
68
|
+
viewer has focus (press on it, or Tab to it). Zoom with the mouse wheel
|
|
69
|
+
(`zoom: false` disables it).
|
|
70
|
+
- **Walk** by clicking the floor: hovering shows a disc under the pointer and a
|
|
71
|
+
cross on the nearest node; clicking walks there. Disable with
|
|
72
|
+
`navigation: false`. Paused while the view moves to the next node.
|
|
73
|
+
- **Programmatically:** `viewer.open(target, { heading })` (awaitable), or
|
|
74
|
+
`viewer.navigateTo(nodeId)` (fire and forget), and
|
|
75
|
+
`viewer.nearestNode(coordinates, level?)` to find the node closest to a place
|
|
76
|
+
(after `viewer.loadGraph()`, which fetches the graph without opening a photo).
|
|
77
|
+
`viewer.lookAt(heading, pitch = 0)` turns the camera the short way round;
|
|
78
|
+
dragging the panorama cancels it.
|
|
79
|
+
|
|
80
|
+
The look direction is a real compass heading, so it is kept when you change
|
|
81
|
+
node: you keep facing the same way.
|
|
82
|
+
|
|
83
|
+
`navigateTo` updates `currentNode` and fires `navigate` right away, while the
|
|
84
|
+
new image loads and fades in. If that image fails to load, the viewer goes back
|
|
85
|
+
to the node still on screen (`navigate` fires again with it) and calls
|
|
86
|
+
`onError`.
|
|
87
|
+
|
|
88
|
+
## Locating a point
|
|
89
|
+
|
|
90
|
+
In `locate` click mode, a click on the panorama gives the geo position of what
|
|
91
|
+
is under it (from the VPS depth estimate) instead of walking: to place a POI
|
|
92
|
+
where the user points, for example.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
viewer.setClickMode('locate');
|
|
96
|
+
viewer.on('locate', ({ coordinates, node }) => {
|
|
97
|
+
console.log(coordinates.lat, coordinates.lng, coordinates.alt, coordinates.level);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
viewer.setClickMode('navigate'); // back to walking
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The cursor becomes a crosshair, and clicks during a transition are ignored. The
|
|
104
|
+
level is the clicked node's when the VPS gives none. Failures go to `onError`.
|
|
105
|
+
|
|
106
|
+
## Measuring
|
|
107
|
+
|
|
108
|
+
In `measure` click mode, two clicks on the panorama give the distance between
|
|
109
|
+
the two points (from the VPS depth estimate). The viewer draws a dot on each
|
|
110
|
+
point and a line between them; a third click clears them, as do changing mode
|
|
111
|
+
and moving to another node.
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
viewer.setClickMode('measure');
|
|
115
|
+
viewer.on('measure', ({ distance }) => showLabel(`${distance.toFixed(2)} m`));
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Drawing over the panorama
|
|
119
|
+
|
|
120
|
+
`setPolygons` draws polygons anchored in the real world: a shelf front, an area
|
|
121
|
+
on the floor, a door. Each vertex needs an altitude, in the same reference as
|
|
122
|
+
the graph nodes'. The polygons follow the user from node to node; a new call
|
|
123
|
+
replaces them, an empty list clears them. The panorama has no depth: a polygon
|
|
124
|
+
behind a wall still shows.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
viewer.setPolygons([{
|
|
128
|
+
coordinates: [
|
|
129
|
+
new Coordinates(48.99068, 2.20736, -1.41),
|
|
130
|
+
new Coordinates(48.99067, 2.20742, -1.41),
|
|
131
|
+
new Coordinates(48.99067, 2.20742, 1.24),
|
|
132
|
+
new Coordinates(48.99068, 2.20736, 1.24),
|
|
133
|
+
],
|
|
134
|
+
color: '#3860BE',
|
|
135
|
+
}]);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Events
|
|
139
|
+
|
|
140
|
+
Each constructor callback (`onNavigate`, `onHeadingChange`, `onReady`,
|
|
141
|
+
`onError`) takes one listener. For more, subscribe with `viewer.on()`, which
|
|
142
|
+
returns an unsubscribe function:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
const off = viewer.on('heading', (heading) => compass.rotate(heading));
|
|
146
|
+
off();
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
| Event | Payload | When |
|
|
150
|
+
| ---------- | --------------------- | -------------------------------------------- |
|
|
151
|
+
| `ready` | — | The first image is on screen (once) |
|
|
152
|
+
| `navigate` | `ViewerNode` | A move to a node starts (click or code) |
|
|
153
|
+
| `heading` | `number` (degrees) | The look heading changes |
|
|
154
|
+
| `locate` | `LocatedPoint` | A click in `locate` mode was located |
|
|
155
|
+
| `measure` | `Measurement` | Two clicks in `measure` mode were measured |
|
|
156
|
+
| `click` | `ViewerClick` | A click in `navigate` mode walked nowhere (above the horizon, or no node there): its heading, pitch and node, to pick your own geometry |
|
|
157
|
+
|
|
158
|
+
## Options
|
|
159
|
+
|
|
160
|
+
| Option | Type | Default | Description |
|
|
161
|
+
| -------------------- | --------------------------- | ------- | --------------------------------------------- |
|
|
162
|
+
| `zoom` | `boolean` | `true` | Mouse-wheel zoom |
|
|
163
|
+
| `maxFov` | `number` | `80` | Widest vertical field of view, in degrees |
|
|
164
|
+
| `navigation` | `boolean` | `true` | Click the floor to walk to the nearest node |
|
|
165
|
+
| `onNavigate` | `(nodeId: number) => void` | | A move to a node starts |
|
|
166
|
+
| `onHeadingChange` | `(heading: number) => void` | | The look heading changes |
|
|
167
|
+
| `onReady` | `() => void` | | The first image is on screen (once) |
|
|
168
|
+
| `onLocate` | `(point: LocatedPoint) => void` | | A click in `locate` mode was located |
|
|
169
|
+
| `onMeasure` | `(measurement: Measurement) => void` | | Two clicks in `measure` mode were measured |
|
|
170
|
+
| `onError` | `(error: Error) => void` | | Graph, image, located point or measurement failed |
|
|
171
|
+
|
|
172
|
+
## API
|
|
173
|
+
|
|
174
|
+
| Member | Description |
|
|
175
|
+
| ----------------------------------- | ----------------------------------------------------------- |
|
|
176
|
+
| `open(target, { heading?, pitch? })` | Open on a node id or the nearest node to a position; resolves once its image is on screen, rejects if the node is unknown or the graph or image fails |
|
|
177
|
+
| `loadGraph(): Promise<ViewerNode[]>` | Fetch the image graph without opening a photo (once; shared with `open()`) |
|
|
178
|
+
| `getNodes(): ViewerNode[]` | All nodes (id, coordinates, level, image, capture heading); empty until the graph is loaded |
|
|
179
|
+
| `currentNode: ViewerNode \| null` | The node the viewer is at (set as soon as a move starts) |
|
|
180
|
+
| `navigateTo(nodeId)` | Move to a node; no-op if unknown or already there |
|
|
181
|
+
| `nearestNode(coordinates, level?)` | Closest node to a place, on `level` when given; null before the graph is loaded |
|
|
182
|
+
| `getHeading(): number` | Current look heading, degrees (0 = north, clockwise) |
|
|
183
|
+
| `lookAt(heading, pitch?)` | Turn to a heading/pitch, animated |
|
|
184
|
+
| `setClickMode(mode)` / `clickMode` | What a click does: `'navigate'` (walk, default), `'locate'` or `'measure'` |
|
|
185
|
+
| `getGraphGeojson()` | The graph as GeoJSON (used by `@wemap/viewer-map`) |
|
|
186
|
+
| `on(event, callback)` | Subscribe to an event; returns an unsubscribe function |
|
|
187
|
+
| `resize()` | Re-measure the container (automatic on resize) |
|
|
188
|
+
| `destroy()` | Release the renderer, images, listeners and canvas |
|
|
189
|
+
|
|
190
|
+
`ViewerDataClient` (graph and image URLs) is exported for standalone use too.
|