@osm-editor-kit/street-imagery-react 0.1.0-alpha.11 → 0.1.0-alpha.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/index.js +144 -79
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useStreetImageryI18n } from './chunk-6EMFFIL2.js';
|
|
2
2
|
export { STREET_IMAGERY_MESSAGES, StreetImageryLocaleProvider, useStreetImageryI18n } from './chunk-6EMFFIL2.js';
|
|
3
3
|
export { useViewerActions, useViewerBearing, useViewerHfov, useViewerLngLat } from './chunk-25UGGXIE.js';
|
|
4
|
-
import { distanceMeters, sequencesToFeatureCollection, emptyLineCollection, adapterById, providerById, providerCoversBbox, fetchedSequencesMinZoom, viewConeGeoJson, viewShapeRadiusMeters, setStreetImageryConfig, viewfieldLayerId, photoLayerId, photoTargetLayerId, featureLayerId, PROVIDER_IDS, mapFeatureMatchesDateRange, isBrowserAvailableProvider,
|
|
4
|
+
import { distanceMeters, sequencesToFeatureCollection, emptyLineCollection, adapterById, providerById, providerCoversBbox, fetchedSequencesMinZoom, viewConeGeoJson, viewShapeRadiusMeters, setStreetImageryConfig, viewfieldLayerId, photoLayerId, photoTargetLayerId, featureLayerId, PROVIDER_IDS, mapFeatureMatchesDateRange, isBrowserAvailableProvider, photoFilter, resolvePhotoPanoramaUrl, photoFullUrlQueryKey, resolvePhotoThumbnailUrl, photoThumbnailQueryKey, formatLocalDateTime, formatMonth, formatRelativeDate, formatDateTooltip, mapillaryPhotoSource, buildViewSuggestions, yearsToMs, SIGN_TARGET, fetchMapFeatureImages, fetchMapillaryMapFeaturesInBbox, bboxAround, fetchImageDetections, bestTargetImage, findLocationOpener, MAP_FEATURE_COLOR, mapillaryValueName, mapillaryIconUrl, dateRangeToSliderPositions, sliderPositionsToDateRange, dateSliderBins, dateSliderPosition, yearsAgoMs, parseIsoDateStartMs, openLocationInNewTab, formatDate, isIsoDate, alignLineToPoints, coneRadiusMeters, emptyPointCollection, mapFeaturesToFeatureCollection, buildMapFeatureLayerFilter, featureSourceId, buildPhotoLayerFilter, photoSourceId, viewfieldSourceId, sequenceTilesSourceId, renameExpressionProperties, sequenceTilesLayerId, sequenceSourceId, sequenceLayerId, viewfieldLineLayerId, VIEWFIELD_MIN_ZOOM, photosToFeatureCollection, photosToViewfieldsFeatureCollection, emptyPolygonCollection } from '@osm-editor-kit/street-imagery';
|
|
5
5
|
import { Source, Layer, useMap } from 'react-map-gl/maplibre';
|
|
6
6
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
7
|
-
import { lazy, useEffect, Fragment as Fragment$1, Suspense, useState, useRef, useEffectEvent } from 'react';
|
|
7
|
+
import { lazy, useEffect, Fragment as Fragment$1, Suspense, useState, useRef, useEffectEvent, useMemo } from 'react';
|
|
8
8
|
import { keepPreviousData, useQuery, useQueries } from '@tanstack/react-query';
|
|
9
9
|
import { create } from 'zustand';
|
|
10
10
|
|
|
@@ -280,8 +280,95 @@ var AGE_SHADE = [
|
|
|
280
280
|
]
|
|
281
281
|
];
|
|
282
282
|
var PHOTO_TARGET_RADIUS_PX = 10;
|
|
283
|
-
var
|
|
284
|
-
var
|
|
283
|
+
var NO_PHOTOS = [];
|
|
284
|
+
var NO_SEQUENCES = [];
|
|
285
|
+
var NO_MAP_FEATURES = [];
|
|
286
|
+
var bboxesOverlap = (a, b) => a[0] <= b[2] && a[2] >= b[0] && a[1] <= b[3] && a[3] >= b[1];
|
|
287
|
+
var sequenceBbox = ({ geometry }) => {
|
|
288
|
+
const lines = geometry.type === "LineString" ? [geometry.coordinates] : geometry.coordinates;
|
|
289
|
+
const bbox = [Infinity, Infinity, -Infinity, -Infinity];
|
|
290
|
+
for (const line of lines) {
|
|
291
|
+
for (const [lng, lat] of line) {
|
|
292
|
+
if (lng === void 0 || lat === void 0) continue;
|
|
293
|
+
bbox[0] = Math.min(bbox[0], lng);
|
|
294
|
+
bbox[1] = Math.min(bbox[1], lat);
|
|
295
|
+
bbox[2] = Math.max(bbox[2], lng);
|
|
296
|
+
bbox[3] = Math.max(bbox[3], lat);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return bbox;
|
|
300
|
+
};
|
|
301
|
+
var buildPhotoLayerData = ({
|
|
302
|
+
photos,
|
|
303
|
+
sequences,
|
|
304
|
+
bbox,
|
|
305
|
+
photoTypes,
|
|
306
|
+
date,
|
|
307
|
+
showPhotos,
|
|
308
|
+
showSequences,
|
|
309
|
+
viewfieldZoom
|
|
310
|
+
}) => {
|
|
311
|
+
const matchesFilters = photoFilter(photoTypes, date);
|
|
312
|
+
const visiblePhotos = showPhotos ? photos.filter(matchesFilters) : [];
|
|
313
|
+
const drawBbox = bbox ? padBbox(bbox, 0.25) : null;
|
|
314
|
+
const drawnPhotos = drawBbox ? visiblePhotos.filter((photo) => lngLatInBbox(photo.lngLat, drawBbox)) : [...visiblePhotos];
|
|
315
|
+
drawnPhotos.sort((a, b) => (a.capturedAt ?? 0) - (b.capturedAt ?? 0));
|
|
316
|
+
const photoCollection = showPhotos ? photosToFeatureCollection(drawnPhotos) : emptyPointCollection();
|
|
317
|
+
const viewfieldCollection = viewfieldZoom != null ? photosToViewfieldsFeatureCollection(visiblePhotos, viewfieldZoom, { bbox }) : emptyPolygonCollection();
|
|
318
|
+
const sequenceCapturedAtById = /* @__PURE__ */ new Map();
|
|
319
|
+
for (const photo of visiblePhotos) {
|
|
320
|
+
if (photo.sequenceId == null || photo.capturedAt == null) continue;
|
|
321
|
+
const prev = sequenceCapturedAtById.get(photo.sequenceId);
|
|
322
|
+
if (prev == null || photo.capturedAt > prev) {
|
|
323
|
+
sequenceCapturedAtById.set(photo.sequenceId, photo.capturedAt);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const filteredSequences = showSequences ? sequences.map((sequence) => {
|
|
327
|
+
if (sequence.capturedAt != null) return sequence;
|
|
328
|
+
const fromPhotos = sequenceCapturedAtById.get(sequence.sequenceId);
|
|
329
|
+
return fromPhotos != null ? { ...sequence, capturedAt: fromPhotos } : sequence;
|
|
330
|
+
}).filter((sequence) => {
|
|
331
|
+
const asPhoto = {
|
|
332
|
+
providerId: sequence.providerId,
|
|
333
|
+
photoId: sequence.sequenceId,
|
|
334
|
+
sequenceId: sequence.sequenceId,
|
|
335
|
+
capturedAt: sequence.capturedAt,
|
|
336
|
+
isPano: sequence.isPano,
|
|
337
|
+
heading: null,
|
|
338
|
+
lngLat: [0, 0]
|
|
339
|
+
};
|
|
340
|
+
return matchesFilters(asPhoto) && (!drawBbox || bboxesOverlap(sequenceBbox(sequence), drawBbox));
|
|
341
|
+
}) : [];
|
|
342
|
+
const photoLngLatsBySequence = /* @__PURE__ */ new Map();
|
|
343
|
+
for (const photo of photos) {
|
|
344
|
+
if (photo.sequenceId == null) continue;
|
|
345
|
+
const list = photoLngLatsBySequence.get(photo.sequenceId);
|
|
346
|
+
if (list) {
|
|
347
|
+
list.push(photo.lngLat);
|
|
348
|
+
} else {
|
|
349
|
+
photoLngLatsBySequence.set(photo.sequenceId, [photo.lngLat]);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const alignedSequences = filteredSequences.map((sequence) => {
|
|
353
|
+
const points = photoLngLatsBySequence.get(sequence.sequenceId);
|
|
354
|
+
if (!points) return sequence;
|
|
355
|
+
const { geometry } = sequence;
|
|
356
|
+
return {
|
|
357
|
+
...sequence,
|
|
358
|
+
geometry: geometry.type === "LineString" ? {
|
|
359
|
+
...geometry,
|
|
360
|
+
coordinates: alignLineToPoints(geometry.coordinates, points)
|
|
361
|
+
} : {
|
|
362
|
+
...geometry,
|
|
363
|
+
coordinates: geometry.coordinates.map(
|
|
364
|
+
(line) => alignLineToPoints(line, points)
|
|
365
|
+
)
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
});
|
|
369
|
+
const sequenceCollection = alignedSequences.length > 0 ? sequencesToFeatureCollection(alignedSequences) : emptyLineCollection();
|
|
370
|
+
return { photoCollection, viewfieldCollection, sequenceCollection };
|
|
371
|
+
};
|
|
285
372
|
var PhotoProviderLayer = ({
|
|
286
373
|
providerId,
|
|
287
374
|
bbox,
|
|
@@ -301,15 +388,44 @@ var PhotoProviderLayer = ({
|
|
|
301
388
|
const photosMinZoom = Math.max(meta.minZoom, minZoom);
|
|
302
389
|
const fetchedLinesMinZoom = fetchedSequencesMinZoom(providerId);
|
|
303
390
|
const sequencesMinZoom = Math.max(fetchedLinesMinZoom, minZoom);
|
|
304
|
-
const { data: photos =
|
|
305
|
-
const { data: sequences =
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const photoCollection = zoom >= photosMinZoom ? photosToFeatureCollection(
|
|
309
|
-
drawBbox ? visiblePhotos.filter((photo) => lngLatInBbox(photo.lngLat, drawBbox)) : visiblePhotos
|
|
310
|
-
) : emptyPointCollection();
|
|
391
|
+
const { data: photos = NO_PHOTOS } = useProviderPhotos(providerId, bbox, zoom, { minZoom });
|
|
392
|
+
const { data: sequences = NO_SEQUENCES } = useProviderSequences(providerId, bbox, zoom, {
|
|
393
|
+
minZoom
|
|
394
|
+
});
|
|
311
395
|
const viewfieldsActive = showViewfields && zoom >= VIEWFIELD_MIN_ZOOM;
|
|
312
|
-
const
|
|
396
|
+
const viewfieldZoom = viewfieldsActive ? Math.floor(zoom * 2) / 2 : null;
|
|
397
|
+
const showPhotos = zoom >= photosMinZoom;
|
|
398
|
+
const showFetchedSequences = showSequences && zoom >= sequencesMinZoom;
|
|
399
|
+
const [west, south, east, north] = bbox ?? [];
|
|
400
|
+
const photoTypesKey = filter?.photoTypes?.join(",");
|
|
401
|
+
const dateFrom = filter?.date?.from;
|
|
402
|
+
const dateTo = filter?.date?.to;
|
|
403
|
+
const { photoCollection, viewfieldCollection, sequenceCollection } = useMemo(
|
|
404
|
+
() => buildPhotoLayerData({
|
|
405
|
+
photos,
|
|
406
|
+
sequences,
|
|
407
|
+
bbox: west !== void 0 && south !== void 0 && east !== void 0 && north !== void 0 ? [west, south, east, north] : null,
|
|
408
|
+
photoTypes: photoTypesKey ? photoTypesKey.split(",") : void 0,
|
|
409
|
+
date: { from: dateFrom, to: dateTo },
|
|
410
|
+
showPhotos,
|
|
411
|
+
showSequences: showFetchedSequences,
|
|
412
|
+
viewfieldZoom
|
|
413
|
+
}),
|
|
414
|
+
[
|
|
415
|
+
photos,
|
|
416
|
+
sequences,
|
|
417
|
+
west,
|
|
418
|
+
south,
|
|
419
|
+
east,
|
|
420
|
+
north,
|
|
421
|
+
photoTypesKey,
|
|
422
|
+
dateFrom,
|
|
423
|
+
dateTo,
|
|
424
|
+
showPhotos,
|
|
425
|
+
showFetchedSequences,
|
|
426
|
+
viewfieldZoom
|
|
427
|
+
]
|
|
428
|
+
);
|
|
313
429
|
const inActiveSequence = [
|
|
314
430
|
"==",
|
|
315
431
|
["get", "sequenceId"],
|
|
@@ -345,63 +461,11 @@ var PhotoProviderLayer = ({
|
|
|
345
461
|
hasActiveSequence ? full * 0.4 : full
|
|
346
462
|
];
|
|
347
463
|
const notShownPhoto = ["!=", ["get", "photoId"], shownPhotoId ?? ""];
|
|
348
|
-
const
|
|
464
|
+
const photoFilter3 = buildPhotoLayerFilter(filter?.photoTypes, filter?.date);
|
|
349
465
|
const photoSrcId = photoSourceId(providerId);
|
|
350
466
|
const viewfieldSrcId = viewfieldSourceId(providerId);
|
|
351
|
-
const sequenceCapturedAtById = /* @__PURE__ */ new Map();
|
|
352
|
-
for (const photo of visiblePhotos) {
|
|
353
|
-
if (photo.sequenceId == null || photo.capturedAt == null) continue;
|
|
354
|
-
const prev = sequenceCapturedAtById.get(photo.sequenceId);
|
|
355
|
-
if (prev == null || photo.capturedAt > prev) {
|
|
356
|
-
sequenceCapturedAtById.set(photo.sequenceId, photo.capturedAt);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
const filteredSequences = showSequences && zoom >= sequencesMinZoom ? sequences.map((sequence) => {
|
|
360
|
-
if (sequence.capturedAt != null) return sequence;
|
|
361
|
-
const fromPhotos = sequenceCapturedAtById.get(sequence.sequenceId);
|
|
362
|
-
return fromPhotos != null ? { ...sequence, capturedAt: fromPhotos } : sequence;
|
|
363
|
-
}).filter((sequence) => {
|
|
364
|
-
const asPhoto = {
|
|
365
|
-
providerId: sequence.providerId,
|
|
366
|
-
photoId: sequence.sequenceId,
|
|
367
|
-
sequenceId: sequence.sequenceId,
|
|
368
|
-
capturedAt: sequence.capturedAt,
|
|
369
|
-
isPano: sequence.isPano,
|
|
370
|
-
heading: null,
|
|
371
|
-
lngLat: [0, 0]
|
|
372
|
-
};
|
|
373
|
-
return photoMatchesFilters(asPhoto, filter?.photoTypes, filter?.date);
|
|
374
|
-
}) : [];
|
|
375
|
-
const photoLngLatsBySequence = /* @__PURE__ */ new Map();
|
|
376
|
-
for (const photo of photos) {
|
|
377
|
-
if (photo.sequenceId == null) continue;
|
|
378
|
-
const list = photoLngLatsBySequence.get(photo.sequenceId);
|
|
379
|
-
if (list) {
|
|
380
|
-
list.push(photo.lngLat);
|
|
381
|
-
} else {
|
|
382
|
-
photoLngLatsBySequence.set(photo.sequenceId, [photo.lngLat]);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
const alignedSequences = filteredSequences.map((sequence) => {
|
|
386
|
-
const points = photoLngLatsBySequence.get(sequence.sequenceId);
|
|
387
|
-
if (!points) return sequence;
|
|
388
|
-
const { geometry } = sequence;
|
|
389
|
-
return {
|
|
390
|
-
...sequence,
|
|
391
|
-
geometry: geometry.type === "LineString" ? {
|
|
392
|
-
...geometry,
|
|
393
|
-
coordinates: alignLineToPoints(geometry.coordinates, points)
|
|
394
|
-
} : {
|
|
395
|
-
...geometry,
|
|
396
|
-
coordinates: geometry.coordinates.map(
|
|
397
|
-
(line) => alignLineToPoints(line, points)
|
|
398
|
-
)
|
|
399
|
-
}
|
|
400
|
-
};
|
|
401
|
-
});
|
|
402
467
|
const sequenceTiles = showSequences ? adapter?.sequenceTiles?.() : null;
|
|
403
468
|
const sequenceTilesMinZoom = sequenceTiles ? Math.max(sequenceTiles.minZoom, minZoom) : 0;
|
|
404
|
-
const sequenceCollection = alignedSequences.length > 0 ? sequencesToFeatureCollection(alignedSequences) : emptyLineCollection();
|
|
405
469
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
406
470
|
meta.coverageTiles ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
407
471
|
/* @__PURE__ */ jsx(
|
|
@@ -448,7 +512,7 @@ var PhotoProviderLayer = ({
|
|
|
448
512
|
"source-layer": sequenceTiles.sourceLayer,
|
|
449
513
|
minzoom: sequenceTilesMinZoom,
|
|
450
514
|
maxzoom: fetchedLinesMinZoom,
|
|
451
|
-
filter: renameExpressionProperties(
|
|
515
|
+
filter: renameExpressionProperties(photoFilter3, sequenceTiles.properties),
|
|
452
516
|
layout: {
|
|
453
517
|
"line-cap": "round",
|
|
454
518
|
"line-join": "round",
|
|
@@ -556,8 +620,7 @@ var PhotoProviderLayer = ({
|
|
|
556
620
|
id: photoTargetLayerId(providerId),
|
|
557
621
|
type: "circle",
|
|
558
622
|
source: photoSrcId,
|
|
559
|
-
filter:
|
|
560
|
-
layout: { "circle-sort-key": PHOTO_SORT_KEY },
|
|
623
|
+
filter: photoFilter3,
|
|
561
624
|
paint: { "circle-radius": PHOTO_TARGET_RADIUS_PX, "circle-opacity": 0 }
|
|
562
625
|
}
|
|
563
626
|
),
|
|
@@ -568,8 +631,7 @@ var PhotoProviderLayer = ({
|
|
|
568
631
|
id: photoLayerId(providerId),
|
|
569
632
|
type: "circle",
|
|
570
633
|
source: photoSrcId,
|
|
571
|
-
filter:
|
|
572
|
-
layout: { "circle-sort-key": PHOTO_SORT_KEY },
|
|
634
|
+
filter: photoFilter3,
|
|
573
635
|
paint: {
|
|
574
636
|
"circle-radius": dotRadius,
|
|
575
637
|
"circle-color": lineAndDotColor
|
|
@@ -588,11 +650,17 @@ var MapFeatureProviderLayer = ({
|
|
|
588
650
|
minZoom
|
|
589
651
|
}) => {
|
|
590
652
|
const meta = providerById[providerId];
|
|
591
|
-
const { data: features =
|
|
653
|
+
const { data: features = NO_MAP_FEATURES } = useProviderMapFeatures(providerId, bbox, zoom, {
|
|
654
|
+
minZoom
|
|
655
|
+
});
|
|
592
656
|
const valueFilter = filter?.mapFeatureValue;
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
|
|
657
|
+
const showFeatures = zoom >= Math.max(meta.minZoom, minZoom);
|
|
658
|
+
const featureCollection = useMemo(() => {
|
|
659
|
+
if (!showFeatures) return emptyPointCollection();
|
|
660
|
+
const drawn = valueFilter ? features.filter((feature) => valueFilter(feature.value)) : [...features];
|
|
661
|
+
drawn.sort((a, b) => (a.lastSeenAt ?? 0) - (b.lastSeenAt ?? 0));
|
|
662
|
+
return mapFeaturesToFeatureCollection(drawn);
|
|
663
|
+
}, [features, valueFilter, showFeatures]);
|
|
596
664
|
const featureFilter = buildMapFeatureLayerFilter(filter?.date);
|
|
597
665
|
const featureSrcId = featureSourceId(providerId);
|
|
598
666
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -614,7 +682,6 @@ var MapFeatureProviderLayer = ({
|
|
|
614
682
|
type: "circle",
|
|
615
683
|
source: featureSrcId,
|
|
616
684
|
filter: featureFilter,
|
|
617
|
-
layout: { "circle-sort-key": FEATURE_SORT_KEY },
|
|
618
685
|
paint: {
|
|
619
686
|
"circle-radius": FEATURE_CIRCLE_RADIUS,
|
|
620
687
|
"circle-color": mapFeatureCircleColor
|
|
@@ -866,10 +933,8 @@ var useAllProviderPhotos = (providerIds, bbox, zoom, photoTypes, date) => {
|
|
|
866
933
|
zoom
|
|
867
934
|
)
|
|
868
935
|
}));
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
return data.filter((photo) => photoMatchesFilters(photo, photoTypes, date));
|
|
872
|
-
});
|
|
936
|
+
const matchesFilters = photoFilter(photoTypes, date);
|
|
937
|
+
const photos = queries.flatMap(({ query }) => (query.data ?? []).filter(matchesFilters));
|
|
873
938
|
const activeQueries = queries.filter(({ providerId }) => enabled.has(providerId));
|
|
874
939
|
const isLoading = activeQueries.some(({ query }) => query.isLoading);
|
|
875
940
|
const isFetching = activeQueries.some(({ query }) => query.isFetching);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@osm-editor-kit/street-imagery-react",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.12",
|
|
4
4
|
"description": "React MapLibre layers and photo viewers for street-level imagery providers.",
|
|
5
5
|
"homepage": "https://github.com/osmberlin/street-space-editor/tree/main/packages/street-imagery-react",
|
|
6
6
|
"license": "MIT",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"zustand": "^5.0.7"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@osm-editor-kit/street-imagery": "^0.1.0-alpha.
|
|
67
|
+
"@osm-editor-kit/street-imagery": "^0.1.0-alpha.9",
|
|
68
68
|
"@panoramax/web-viewer": "^5",
|
|
69
69
|
"@tanstack/react-query": "^5",
|
|
70
70
|
"mapillary-js": "^4",
|