@osm-editor-kit/street-imagery-react 0.1.0-alpha.8 → 1.0.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +118 -9
  3. package/dist/MapillaryPanel-SOHGB7JA.js +3 -0
  4. package/dist/PanoramaxPanel-5P5LWMRY.js +3 -0
  5. package/dist/StreetLevelImagerySelectionOverlay.d.ts +3 -1
  6. package/dist/StreetLevelImagerySourcesAndLayers.d.ts +10 -0
  7. package/dist/StreetLevelImageryViewCone.d.ts +3 -1
  8. package/dist/StreetLevelImageryViewer.d.ts +18 -4
  9. package/dist/{chunk-ZAIXGYAH.js → chunk-3DFVM6VK.js} +59 -15
  10. package/dist/{chunk-25UGGXIE.js → chunk-GYUS2JVV.js} +24 -4
  11. package/dist/chunk-LZR5SZDS.js +498 -0
  12. package/dist/chunk-R6BDVYWM.js +665 -0
  13. package/dist/chunk-XLBFXACK.js +56 -0
  14. package/dist/filters/PhotoDateRangeFilter.d.ts +10 -2
  15. package/dist/filters/dateSliderPointer.d.ts +21 -0
  16. package/dist/hooks/useMapViewportBbox.d.ts +3 -5
  17. package/dist/hooks/useProviderData.d.ts +14 -3
  18. package/dist/index.d.ts +12 -13
  19. package/dist/index.js +3942 -1461
  20. package/dist/mapillary/useMapillaryFeatures.d.ts +5 -5
  21. package/dist/panels/MapillaryPanel.d.ts +7 -2
  22. package/dist/panels/PanoramaxPanel.d.ts +16 -8
  23. package/dist/panels/PanoramaxWebViewerPanel.d.ts +25 -0
  24. package/dist/panels/panoramaxDataProvider.d.ts +44 -0
  25. package/dist/panels/panoramaxItem.d.ts +98 -0
  26. package/dist/panels/photoView.d.ts +19 -0
  27. package/dist/panoramax-web-viewer/index.d.ts +1 -0
  28. package/dist/{chunk-EQ2JKLGT.js → panoramax-web-viewer.js} +299 -92
  29. package/dist/photo-details.js +222 -151
  30. package/dist/streetImageryClick.d.ts +4 -0
  31. package/dist/viewer-panels/index.d.ts +5 -0
  32. package/dist/viewer-panels.js +4 -0
  33. package/dist/viewpoints/FloatingPhotoViewer.d.ts +39 -11
  34. package/dist/viewpoints/floatingViewerPosition.d.ts +18 -0
  35. package/dist/viewpoints/usePhotosLookingAt.d.ts +26 -0
  36. package/package.json +32 -6
  37. package/dist/MapillaryPanel-N45NQY4C.js +0 -2
  38. package/dist/PanoramaxPanel-MFI4L67Z.js +0 -2
  39. package/dist/chunk-53RA4OSJ.js +0 -304
@@ -0,0 +1,665 @@
1
+ import { watchMapillaryJsView, panoramaxZoomLevel } from './chunk-XLBFXACK.js';
2
+ import { useViewerActions } from './chunk-GYUS2JVV.js';
3
+ import { c } from 'react/compiler-runtime';
4
+ import { providerExternalLink, getStreetImageryConfig } from '@osm-editor-kit/street-imagery';
5
+ import 'mapillary-js/dist/mapillary.css';
6
+ import { DataProviderBase, S2GeometryProvider, Viewer } from 'mapillary-js';
7
+ import { useRef, useState, useEffectEvent, useEffect } from 'react';
8
+ import { jsxs, jsx } from 'react/jsx-runtime';
9
+
10
+ // src/panels/panoramaxItem.ts
11
+ var DEFAULT_FIELD_OF_VIEW_DEG = 70;
12
+ var toMs = (iso) => {
13
+ const ms = iso ? Date.parse(iso) : Number.NaN;
14
+ return Number.isNaN(ms) ? null : ms;
15
+ };
16
+ var orientation = (item) => item.properties?.["pers:interior_orientation"];
17
+ var isPanoramaxItemSpherical = (item) => orientation(item)?.field_of_view === 360;
18
+ var panoramaxItemFieldOfView = (item) => orientation(item)?.field_of_view ?? DEFAULT_FIELD_OF_VIEW_DEG;
19
+ var panoramaxItemSize = (item) => orientation(item)?.sensor_array_dimensions ?? (isPanoramaxItemSpherical(item) ? [2, 1] : [4, 3]);
20
+ var panoramaxItemNeighbour = (item, rel) => item.links?.find((link) => link.rel === rel)?.id ?? null;
21
+ var SD_WIDTH = 2048;
22
+ var panoramaxItemImageUrl = (item) => {
23
+ const {
24
+ hd,
25
+ sd,
26
+ thumb
27
+ } = item.assets ?? {};
28
+ return sd?.href ?? hd?.href ?? thumb?.href ?? "";
29
+ };
30
+ var TILE_SIZE = 1024;
31
+ var tileSpan = ([width, height], z) => TILE_SIZE * 2 ** (Math.ceil(Math.log2(Math.max(width, height))) - z);
32
+ var panoramaxViewerSize = (item) => {
33
+ const [width, height] = panoramaxItemSize(item);
34
+ const scale = 2 ** Math.ceil(Math.log2(Math.max(width, height))) / Math.max(width, height);
35
+ return [Math.round(width * scale), Math.round(height * scale)];
36
+ };
37
+ var panoramaxLevelNeedsOriginal = (size, z) => size[0] / (tileSpan(size, z) / TILE_SIZE) > SD_WIDTH;
38
+ var panoramaxTilesOfLevel = (size, z) => {
39
+ const [width, height] = size;
40
+ const span = tileSpan(size, z);
41
+ const tiles = [];
42
+ for (let y = 0; y < Math.ceil(height / span); y++) {
43
+ for (let x = 0; x < Math.ceil(width / span); x++) {
44
+ tiles.push({
45
+ x,
46
+ y
47
+ });
48
+ }
49
+ }
50
+ return tiles;
51
+ };
52
+ var panoramaxTileRect = (size, tile, original) => {
53
+ const [width, height] = size;
54
+ const span = tileSpan(size, tile.z);
55
+ const x = tile.x * span;
56
+ const y = tile.y * span;
57
+ const cutWidth = Math.min(span, width - x);
58
+ const cutHeight = Math.min(span, height - y);
59
+ const scaleX = original.width / width;
60
+ const scaleY = original.height / height;
61
+ return {
62
+ x: x * scaleX,
63
+ y: y * scaleY,
64
+ width: cutWidth * scaleX,
65
+ height: cutHeight * scaleY,
66
+ outWidth: Math.max(1, Math.round(cutWidth / span * TILE_SIZE)),
67
+ outHeight: Math.max(1, Math.round(cutHeight / span * TILE_SIZE))
68
+ };
69
+ };
70
+ var panoramaxItemFocal = (item) => {
71
+ const fieldOfView = orientation(item)?.field_of_view || DEFAULT_FIELD_OF_VIEW_DEG;
72
+ const [width, height] = panoramaxItemSize(item);
73
+ const focalByWidth = 0.5 / Math.tan(Math.min(fieldOfView, 170) * Math.PI / 360);
74
+ return focalByWidth * (width / Math.max(width, height));
75
+ };
76
+ var creatorOf = (item) => item.properties?.["geovisio:producer"] ?? item.providers?.at(-1)?.name;
77
+ var panoramaxPhotoFromItem = (item) => {
78
+ const properties = item.properties ?? {};
79
+ const camera = orientation(item);
80
+ const cameraName = [camera?.camera_manufacturer, camera?.camera_model].filter(Boolean).join(" ");
81
+ const isPano = isPanoramaxItemSpherical(item);
82
+ const creatorName = creatorOf(item);
83
+ const uploadedAt = toMs(properties.created);
84
+ const licenseUrl = item.links?.find((link) => link.rel === "license")?.href;
85
+ const instance = item.links?.find((link) => link.rel === "via")?.instance_name;
86
+ const exifEntries = Object.entries(properties.exif ?? {}).filter(([, value]) => typeof value === "string" || typeof value === "number").map(([key, value]) => [key, String(value)]);
87
+ const details = {
88
+ ...properties.license ? {
89
+ license: properties.license
90
+ } : {},
91
+ ...licenseUrl ? {
92
+ licenseUrl
93
+ } : {},
94
+ ...properties.datetimetz ? {
95
+ capturedAtLocal: properties.datetimetz
96
+ } : {},
97
+ ...uploadedAt != null ? {
98
+ uploadedAt
99
+ } : {},
100
+ ...cameraName ? {
101
+ camera: cameraName
102
+ } : {},
103
+ ...!isPano && camera?.field_of_view ? {
104
+ fieldOfViewDeg: camera.field_of_view
105
+ } : {},
106
+ ...properties["quality:horizontal_accuracy"] != null ? {
107
+ positionAccuracyMeters: properties["quality:horizontal_accuracy"]
108
+ } : {},
109
+ ...instance ? {
110
+ instance
111
+ } : {},
112
+ ...camera?.focal_length != null ? {
113
+ focalLengthMm: camera.focal_length
114
+ } : {},
115
+ ...properties["original_file:name"] ? {
116
+ originalFileName: properties["original_file:name"]
117
+ } : {},
118
+ ...properties["original_file:size"] != null ? {
119
+ originalFileSizeBytes: properties["original_file:size"]
120
+ } : {},
121
+ ...properties["geovisio:rank_in_collection"] != null ? {
122
+ rankInSequence: properties["geovisio:rank_in_collection"]
123
+ } : {},
124
+ ...exifEntries.length > 0 ? {
125
+ exif: Object.fromEntries(exifEntries)
126
+ } : {}
127
+ };
128
+ return {
129
+ providerId: "panoramax",
130
+ photoId: item.id,
131
+ sequenceId: item.collection ?? null,
132
+ capturedAt: toMs(properties.datetime),
133
+ isPano,
134
+ heading: properties["view:azimuth"] ?? null,
135
+ lngLat: item.geometry.coordinates,
136
+ ...creatorName ? {
137
+ creatorName
138
+ } : {},
139
+ details
140
+ };
141
+ };
142
+
143
+ // src/panels/panoramaxDataProvider.ts
144
+ var IDS_PER_REQUEST = 40;
145
+ var SEQUENCE_PREFIX = "panoramax-around:";
146
+ var fetchFile = async (url) => {
147
+ const response = await fetch(url);
148
+ if (!response.ok) {
149
+ throw new Error(`Panoramax picture file: HTTP ${response.status}`);
150
+ }
151
+ return response;
152
+ };
153
+ var TILE_PREFIX = "panoramax-tile:";
154
+ var PanoramaxDataProvider = class extends DataProviderBase {
155
+ endpoint;
156
+ items = /* @__PURE__ */ new Map();
157
+ itemRequests = /* @__PURE__ */ new Map();
158
+ imageBuffers = /* @__PURE__ */ new Map();
159
+ pictures = /* @__PURE__ */ new Map();
160
+ constructor({
161
+ endpoint
162
+ }) {
163
+ super(new S2GeometryProvider());
164
+ this.endpoint = endpoint.replace(/\/$/, "");
165
+ }
166
+ /** The Panoramax data of a picture the viewer has loaded. */
167
+ getItem(imageId) {
168
+ return this.items.get(imageId);
169
+ }
170
+ // Only the arrows to pictures nearby need these, and those need a 3D reconstruction.
171
+ getCoreImages(cellId) {
172
+ return Promise.resolve({
173
+ cell_id: cellId,
174
+ images: []
175
+ });
176
+ }
177
+ async getImages(imageIds) {
178
+ const items = await this.loadItems(imageIds);
179
+ return items.map((item) => ({
180
+ node: this.toImageEnt(item),
181
+ node_id: item.id
182
+ }));
183
+ }
184
+ getSpatialImages(imageIds) {
185
+ return this.getImages(imageIds);
186
+ }
187
+ async getSequence(sequenceId) {
188
+ const imageId = sequenceId.slice(SEQUENCE_PREFIX.length);
189
+ const [item] = await this.loadItems([imageId]);
190
+ if (!item) {
191
+ throw new Error(`Panoramax picture ${imageId} not found`);
192
+ }
193
+ const around = [panoramaxItemNeighbour(item, "prev"), item.id, panoramaxItemNeighbour(item, "next")];
194
+ return {
195
+ id: sequenceId,
196
+ image_ids: around.filter((id) => id != null)
197
+ };
198
+ }
199
+ // The viewer asks for the same file more than once while it starts; one download serves all.
200
+ getImageBuffer(url) {
201
+ const running = this.imageBuffers.get(url);
202
+ if (running) {
203
+ return running;
204
+ }
205
+ const load = url.startsWith(TILE_PREFIX) ? this.cutTile(url) : fetchFile(url).then((response) => response.arrayBuffer());
206
+ const request = load.finally(() => this.imageBuffers.delete(url));
207
+ this.imageBuffers.set(url, request);
208
+ return request;
209
+ }
210
+ async getImageTiles({
211
+ imageId,
212
+ z
213
+ }) {
214
+ const [item] = await this.loadItems([imageId]);
215
+ const tiles = item ? panoramaxTilesOfLevel(panoramaxViewerSize(item), z) : [];
216
+ return {
217
+ node_id: imageId,
218
+ node: tiles.map(({
219
+ x,
220
+ y
221
+ }) => ({
222
+ url: `${TILE_PREFIX}${imageId}/${z}/${x}/${y}`,
223
+ x,
224
+ y,
225
+ z
226
+ }))
227
+ };
228
+ }
229
+ async cutTile(url) {
230
+ const [imageId = "", z, x, y] = url.slice(TILE_PREFIX.length).split("/");
231
+ const item = this.items.get(imageId);
232
+ if (!item) {
233
+ throw new Error(`Panoramax picture ${imageId} not loaded`);
234
+ }
235
+ const size = panoramaxViewerSize(item);
236
+ const {
237
+ hd,
238
+ sd
239
+ } = item.assets ?? {};
240
+ const file = (panoramaxLevelNeedsOriginal(size, Number(z)) ? hd : sd) ?? hd ?? sd;
241
+ const original = await this.loadPicture(file?.href ?? "");
242
+ const rect = panoramaxTileRect(size, {
243
+ x: Number(x),
244
+ y: Number(y),
245
+ z: Number(z)
246
+ }, {
247
+ width: original.width,
248
+ height: original.height
249
+ });
250
+ const canvas = new OffscreenCanvas(rect.outWidth, rect.outHeight);
251
+ canvas.getContext("2d")?.drawImage(original, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.outWidth, rect.outHeight);
252
+ const blob = await canvas.convertToBlob({
253
+ type: "image/jpeg",
254
+ quality: 0.9
255
+ });
256
+ return blob.arrayBuffer();
257
+ }
258
+ loadPicture(url) {
259
+ const known = this.pictures.get(url);
260
+ if (known) {
261
+ return known;
262
+ }
263
+ const picture = fetchFile(url).then((response) => response.blob()).then((blob) => createImageBitmap(blob));
264
+ this.pictures.set(url, picture);
265
+ picture.catch(() => this.pictures.delete(url));
266
+ for (const [oldUrl, old] of [...this.pictures].slice(0, -3)) {
267
+ this.pictures.delete(oldUrl);
268
+ void old.then((bitmap) => bitmap.close()).catch(() => {
269
+ });
270
+ }
271
+ return picture;
272
+ }
273
+ getMesh() {
274
+ return Promise.resolve({
275
+ faces: [],
276
+ vertices: []
277
+ });
278
+ }
279
+ getCluster(url) {
280
+ return Promise.resolve({
281
+ id: url,
282
+ points: {},
283
+ reference: {
284
+ lat: 0,
285
+ lng: 0,
286
+ alt: 0
287
+ }
288
+ });
289
+ }
290
+ async loadItems(imageIds) {
291
+ const missing = [...new Set(imageIds.filter((id) => !this.items.has(id) && !this.itemRequests.has(id)))];
292
+ for (let start = 0; start < missing.length; start += IDS_PER_REQUEST) {
293
+ const ids = missing.slice(start, start + IDS_PER_REQUEST);
294
+ const request = fetch(`${this.endpoint}/search?ids=${ids.join(",")}&limit=${ids.length}`).then((response) => {
295
+ if (!response.ok) {
296
+ throw new Error(`Panoramax search: HTTP ${response.status}`);
297
+ }
298
+ return response.json();
299
+ }).then((result) => {
300
+ for (const item of result.features ?? []) {
301
+ this.items.set(item.id, item);
302
+ }
303
+ }).finally(() => {
304
+ for (const id of ids) {
305
+ this.itemRequests.delete(id);
306
+ }
307
+ });
308
+ for (const id of ids) {
309
+ this.itemRequests.set(id, request);
310
+ }
311
+ }
312
+ await Promise.all(imageIds.flatMap((id) => this.itemRequests.get(id) ?? []));
313
+ return imageIds.flatMap((id) => this.items.get(id) ?? []);
314
+ }
315
+ toImageEnt(item) {
316
+ const [lng, lat] = item.geometry.coordinates;
317
+ const [width, height] = panoramaxViewerSize(item);
318
+ const spherical = isPanoramaxItemSpherical(item);
319
+ const properties = item.properties ?? {};
320
+ const none = {
321
+ id: "",
322
+ url: ""
323
+ };
324
+ return {
325
+ id: item.id,
326
+ geometry: {
327
+ lat,
328
+ lng
329
+ },
330
+ sequence: {
331
+ id: `${SEQUENCE_PREFIX}${item.id}`
332
+ },
333
+ altitude: 0,
334
+ camera_type: spherical ? "spherical" : "perspective",
335
+ camera_parameters: spherical ? [] : [panoramaxItemFocal(item), 0, 0],
336
+ captured_at: Date.parse(properties.datetime ?? "") || 0,
337
+ compass_angle: properties["view:azimuth"] ?? 0,
338
+ cluster: none,
339
+ creator: {
340
+ id: "",
341
+ username: properties["geovisio:producer"] ?? ""
342
+ },
343
+ // Panoramax serves its pictures upright.
344
+ exif_orientation: 1,
345
+ width,
346
+ height,
347
+ mesh: none,
348
+ owner: {
349
+ id: ""
350
+ },
351
+ thumb: {
352
+ id: item.id,
353
+ url: panoramaxItemImageUrl(item)
354
+ }
355
+ };
356
+ }
357
+ };
358
+ var PanoramaxPanel = (t0) => {
359
+ const $ = c(33);
360
+ const {
361
+ photo,
362
+ onPhotoSelected,
363
+ onEaseMapToPoint,
364
+ onViewerPhoto,
365
+ onViewerView,
366
+ hideAttribution: t1
367
+ } = t0;
368
+ const hideAttribution = t1 === void 0 ? false : t1;
369
+ const containerRef = useRef(null);
370
+ const viewerRef = useRef(null);
371
+ const dataProviderRef = useRef(null);
372
+ const navigableRef = useRef(false);
373
+ const pendingImageIdRef = useRef(null);
374
+ const lastViewerPhotoIdRef = useRef(null);
375
+ const bearingRafRef = useRef(null);
376
+ const pendingBearingRef = useRef(null);
377
+ const actions = useViewerActions();
378
+ const initialPhotoIdRef = useRef(photo.photoId);
379
+ const [shownPhoto, setShownPhoto] = useState(null);
380
+ const emitPhotoSelected = useEffectEvent(onPhotoSelected);
381
+ const emitEaseMapToPoint = useEffectEvent(onEaseMapToPoint);
382
+ let t2;
383
+ if ($[0] !== onViewerPhoto) {
384
+ t2 = (viewerPhoto) => onViewerPhoto?.(viewerPhoto);
385
+ $[0] = onViewerPhoto;
386
+ $[1] = t2;
387
+ } else {
388
+ t2 = $[1];
389
+ }
390
+ const emitViewerPhoto = useEffectEvent(t2);
391
+ let t3;
392
+ if ($[2] !== actions) {
393
+ t3 = function resetViewerStoreOnProviderChange() {
394
+ return () => {
395
+ actions.reset();
396
+ };
397
+ };
398
+ $[2] = actions;
399
+ $[3] = t3;
400
+ } else {
401
+ t3 = $[3];
402
+ }
403
+ let t4;
404
+ if ($[4] !== actions || $[5] !== photo.providerId) {
405
+ t4 = [actions, photo.providerId];
406
+ $[4] = actions;
407
+ $[5] = photo.providerId;
408
+ $[6] = t4;
409
+ } else {
410
+ t4 = $[6];
411
+ }
412
+ useEffect(t3, t4);
413
+ let t5;
414
+ if ($[7] !== actions || $[8] !== emitEaseMapToPoint || $[9] !== emitPhotoSelected || $[10] !== emitViewerPhoto) {
415
+ t5 = function mountViewer() {
416
+ const container = containerRef.current;
417
+ if (!container) {
418
+ return;
419
+ }
420
+ const dataProvider = new PanoramaxDataProvider({
421
+ endpoint: `${getStreetImageryConfig().panoramaxApiBase}/api`
422
+ });
423
+ dataProviderRef.current = dataProvider;
424
+ const viewer = new Viewer({
425
+ container,
426
+ dataProvider,
427
+ imageId: initialPhotoIdRef.current,
428
+ component: {
429
+ attribution: false,
430
+ cache: {
431
+ depth: {
432
+ sequence: 1,
433
+ spherical: 0,
434
+ step: 0,
435
+ turn: 0
436
+ }
437
+ },
438
+ cover: false,
439
+ sequence: {
440
+ visible: true
441
+ }
442
+ }
443
+ });
444
+ viewerRef.current = viewer;
445
+ lastViewerPhotoIdRef.current = initialPhotoIdRef.current;
446
+ const flushPendingMove = () => {
447
+ const pendingId = pendingImageIdRef.current;
448
+ if (!pendingId) {
449
+ return;
450
+ }
451
+ pendingImageIdRef.current = null;
452
+ viewer.moveTo(pendingId).catch(_temp);
453
+ };
454
+ const onNavigable = (event) => {
455
+ navigableRef.current = event.navigable;
456
+ if (event.navigable) {
457
+ flushPendingMove();
458
+ }
459
+ };
460
+ const onImage = (event_0) => {
461
+ const {
462
+ image
463
+ } = event_0;
464
+ lastViewerPhotoIdRef.current = image.id;
465
+ const item = dataProvider.getItem(image.id);
466
+ if (!item) {
467
+ return;
468
+ }
469
+ const viewerPhoto_0 = panoramaxPhotoFromItem(item);
470
+ emitPhotoSelected({
471
+ provider: "panoramax",
472
+ sequenceId: viewerPhoto_0.sequenceId ?? `photo:${image.id}`,
473
+ photoId: image.id
474
+ });
475
+ setShownPhoto(viewerPhoto_0);
476
+ emitViewerPhoto(viewerPhoto_0);
477
+ actions.setPov({
478
+ lngLat: viewerPhoto_0.lngLat,
479
+ ...!viewerPhoto_0.isPano && viewerPhoto_0.heading != null ? {
480
+ bearing: viewerPhoto_0.heading
481
+ } : {}
482
+ });
483
+ emitEaseMapToPoint(...viewerPhoto_0.lngLat);
484
+ };
485
+ const flushBearing = () => {
486
+ bearingRafRef.current = null;
487
+ if (pendingBearingRef.current != null) {
488
+ actions.setPov({
489
+ bearing: pendingBearingRef.current
490
+ });
491
+ pendingBearingRef.current = null;
492
+ }
493
+ viewer.getFieldOfView().then((fov) => {
494
+ actions.setPov({
495
+ hfov: fov
496
+ });
497
+ }).catch(_temp2);
498
+ };
499
+ const onBearing = (event_1) => {
500
+ pendingBearingRef.current = event_1.bearing;
501
+ if (bearingRafRef.current == null) {
502
+ bearingRafRef.current = requestAnimationFrame(flushBearing);
503
+ }
504
+ };
505
+ viewer.on("navigable", onNavigable);
506
+ viewer.on("image", onImage);
507
+ viewer.on("bearing", onBearing);
508
+ const resizeObserver = new ResizeObserver(() => {
509
+ viewer.resize();
510
+ });
511
+ resizeObserver.observe(container);
512
+ return () => {
513
+ if (bearingRafRef.current != null) {
514
+ cancelAnimationFrame(bearingRafRef.current);
515
+ bearingRafRef.current = null;
516
+ }
517
+ resizeObserver.disconnect();
518
+ viewer.off("navigable", onNavigable);
519
+ viewer.off("image", onImage);
520
+ viewer.off("bearing", onBearing);
521
+ viewer.remove();
522
+ viewerRef.current = null;
523
+ };
524
+ };
525
+ $[7] = actions;
526
+ $[8] = emitEaseMapToPoint;
527
+ $[9] = emitPhotoSelected;
528
+ $[10] = emitViewerPhoto;
529
+ $[11] = t5;
530
+ } else {
531
+ t5 = $[11];
532
+ }
533
+ let t6;
534
+ if ($[12] !== actions) {
535
+ t6 = [actions];
536
+ $[12] = actions;
537
+ $[13] = t6;
538
+ } else {
539
+ t6 = $[13];
540
+ }
541
+ useEffect(t5, t6);
542
+ let t7;
543
+ if ($[14] !== onViewerView) {
544
+ t7 = (view) => onViewerView?.(view);
545
+ $[14] = onViewerView;
546
+ $[15] = t7;
547
+ } else {
548
+ t7 = $[15];
549
+ }
550
+ const emitViewerView = useEffectEvent(t7);
551
+ const reportsView = onViewerView !== void 0;
552
+ let t8;
553
+ if ($[16] !== emitViewerView || $[17] !== reportsView) {
554
+ t8 = function reportViewInPhoto() {
555
+ const viewer_0 = viewerRef.current;
556
+ if (!viewer_0 || !reportsView) {
557
+ return;
558
+ }
559
+ const read = async () => {
560
+ const [image_0, t92, fov_0] = await Promise.all([viewer_0.getImage(), viewer_0.getPointOfView(), viewer_0.getFieldOfView()]);
561
+ const {
562
+ bearing,
563
+ tilt
564
+ } = t92;
565
+ const item_0 = dataProviderRef.current?.getItem(image_0.id);
566
+ return item_0 ? {
567
+ providerId: "panoramax",
568
+ photoId: image_0.id,
569
+ heading: bearing,
570
+ pitch: tilt,
571
+ zoom: panoramaxZoomLevel(fov_0, panoramaxItemFieldOfView(item_0))
572
+ } : null;
573
+ };
574
+ return watchMapillaryJsView(viewer_0, read, (view_0) => emitViewerView(view_0));
575
+ };
576
+ $[16] = emitViewerView;
577
+ $[17] = reportsView;
578
+ $[18] = t8;
579
+ } else {
580
+ t8 = $[18];
581
+ }
582
+ let t9;
583
+ if ($[19] !== actions || $[20] !== reportsView) {
584
+ t9 = [actions, reportsView];
585
+ $[19] = actions;
586
+ $[20] = reportsView;
587
+ $[21] = t9;
588
+ } else {
589
+ t9 = $[21];
590
+ }
591
+ useEffect(t8, t9);
592
+ let t10;
593
+ let t11;
594
+ if ($[22] !== actions || $[23] !== photo.photoId) {
595
+ t10 = function syncExternalPhotoSelection() {
596
+ const viewer_1 = viewerRef.current;
597
+ if (!viewer_1 || photo.photoId === lastViewerPhotoIdRef.current) {
598
+ return;
599
+ }
600
+ actions.reset();
601
+ lastViewerPhotoIdRef.current = photo.photoId;
602
+ if (navigableRef.current) {
603
+ viewer_1.moveTo(photo.photoId).catch(_temp3);
604
+ } else {
605
+ pendingImageIdRef.current = photo.photoId;
606
+ }
607
+ };
608
+ t11 = [actions, photo.photoId];
609
+ $[22] = actions;
610
+ $[23] = photo.photoId;
611
+ $[24] = t10;
612
+ $[25] = t11;
613
+ } else {
614
+ t10 = $[24];
615
+ t11 = $[25];
616
+ }
617
+ useEffect(t10, t11);
618
+ const attribution = hideAttribution ? null : shownPhoto;
619
+ const license = attribution?.details?.license;
620
+ let t12;
621
+ let t13;
622
+ if ($[26] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
623
+ t12 = {
624
+ aspectRatio: "4 / 3"
625
+ };
626
+ t13 = /* @__PURE__ */ jsx("div", { ref: containerRef, className: "h-full w-full" });
627
+ $[26] = t12;
628
+ $[27] = t13;
629
+ } else {
630
+ t12 = $[26];
631
+ t13 = $[27];
632
+ }
633
+ let t14;
634
+ if ($[28] !== attribution || $[29] !== license) {
635
+ t14 = attribution ? /* @__PURE__ */ jsxs("div", { className: "absolute right-0 bottom-0 flex gap-1.5 rounded-tl bg-black/50 px-1.5 py-0.5 text-[11px] leading-4 text-white", children: [
636
+ /* @__PURE__ */ jsx("a", { className: "underline-offset-2 hover:underline", href: providerExternalLink(attribution), rel: "noreferrer", target: "_blank", children: ["Panoramax", attribution.creatorName].filter(Boolean).join(" \xB7 ") }),
637
+ license ? attribution.details?.licenseUrl ? /* @__PURE__ */ jsx("a", { className: "underline-offset-2 hover:underline", href: attribution.details.licenseUrl, rel: "noreferrer", target: "_blank", children: license }) : /* @__PURE__ */ jsx("span", { children: license }) : null
638
+ ] }) : null;
639
+ $[28] = attribution;
640
+ $[29] = license;
641
+ $[30] = t14;
642
+ } else {
643
+ t14 = $[30];
644
+ }
645
+ let t15;
646
+ if ($[31] !== t14) {
647
+ t15 = /* @__PURE__ */ jsxs("div", { className: "relative min-h-48 overflow-hidden rounded-lg border border-slate-200 bg-slate-900", style: t12, children: [
648
+ t13,
649
+ t14
650
+ ] });
651
+ $[31] = t14;
652
+ $[32] = t15;
653
+ } else {
654
+ t15 = $[32];
655
+ }
656
+ return t15;
657
+ };
658
+ function _temp() {
659
+ }
660
+ function _temp2() {
661
+ }
662
+ function _temp3() {
663
+ }
664
+
665
+ export { PanoramaxDataProvider, PanoramaxPanel, panoramaxPhotoFromItem };