@osm-editor-kit/street-imagery-react 0.1.0-alpha.1 → 0.1.0-alpha.11
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 +178 -3
- package/dist/MapillaryPanel-FAXVZH37.js +2 -0
- package/dist/PanoramaxPanel-TWKTSOXM.js +2 -0
- package/dist/StreetLevelImagerySelectionOverlay.d.ts +22 -3
- package/dist/StreetLevelImagerySourcesAndLayers.d.ts +24 -1
- package/dist/StreetLevelImageryViewCone.d.ts +13 -1
- package/dist/StreetLevelImageryViewer.d.ts +23 -1
- package/dist/chunk-6EMFFIL2.js +147 -0
- package/dist/chunk-SGIB7AVC.js +309 -0
- package/dist/chunk-XQXYV6SR.js +466 -0
- package/dist/filters/PhotoDateRangeFilter.d.ts +46 -0
- package/dist/hooks/useAllProviderMapFeatures.d.ts +0 -4
- package/dist/hooks/useProviderData.d.ts +14 -3
- package/dist/i18n/PhotoCount.d.ts +12 -0
- package/dist/i18n/PhotoDate.d.ts +16 -0
- package/dist/i18n/StreetImageryLocaleProvider.d.ts +21 -0
- package/dist/i18n/messages.d.ts +45 -0
- package/dist/index.d.ts +19 -4
- package/dist/index.js +1546 -144
- package/dist/mapillary/MapillaryFeatureBar.d.ts +16 -0
- package/dist/mapillary/SelectedMapFeatureLayer.d.ts +19 -0
- package/dist/mapillary/featureBarLabels.d.ts +16 -0
- package/dist/mapillary/useMapillaryFeatures.d.ts +54 -0
- package/dist/openers/LocationPickOnMap.d.ts +10 -0
- package/dist/openers/useLocationPickStore.d.ts +9 -0
- package/dist/panels/MapillaryPanel.d.ts +19 -1
- package/dist/panels/PanoramaxPanel.d.ts +14 -4
- package/dist/panels/PanoramaxWebViewerPanel.d.ts +20 -0
- package/dist/panels/mapillaryLookAt.d.ts +41 -0
- package/dist/panels/panoramaxDataProvider.d.ts +44 -0
- package/dist/panels/panoramaxItem.d.ts +96 -0
- package/dist/panels/panoramaxLimitPanning.d.ts +54 -0
- package/dist/panels/panoramaxPhotoFromMetadata.d.ts +8 -0
- package/dist/panoramax-web-viewer/index.d.ts +1 -0
- package/dist/panoramax-web-viewer.js +314 -0
- package/dist/photo-details/PhotoDetailsDialog.d.ts +21 -0
- package/dist/photo-details/index.d.ts +6 -0
- package/dist/photo-details/labels.d.ts +33 -0
- package/dist/photo-details.js +235 -0
- package/dist/streetImageryClick.d.ts +4 -0
- package/dist/viewer-panels/index.d.ts +5 -0
- package/dist/viewer-panels.js +3 -0
- package/dist/viewpoints/FloatingPhotoViewer.d.ts +73 -0
- package/dist/viewpoints/ViewpointLayer.d.ts +17 -0
- package/dist/viewpoints/useViewSuggestions.d.ts +23 -0
- package/dist/viewpoints/useViewpointSessionStore.d.ts +35 -0
- package/dist/viewpoints/viewDirectionLabels.d.ts +4 -0
- package/package.json +37 -7
- package/dist/MapillaryPanel-QX6NESX7.js +0 -2
- package/dist/PanoramaxPanel-J6ANR6LB.js +0 -2
- package/dist/chunk-BS6LPDMY.js +0 -143
- package/dist/chunk-ZH3TPW4D.js +0 -165
package/dist/index.js
CHANGED
|
@@ -1,66 +1,129 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
1
|
+
import { useStreetImageryI18n } from './chunk-6EMFFIL2.js';
|
|
2
|
+
export { STREET_IMAGERY_MESSAGES, StreetImageryLocaleProvider, useStreetImageryI18n } from './chunk-6EMFFIL2.js';
|
|
3
3
|
export { useViewerActions, useViewerBearing, useViewerHfov, useViewerLngLat } from './chunk-25UGGXIE.js';
|
|
4
|
-
import {
|
|
4
|
+
import { distanceMeters, sequencesToFeatureCollection, emptyLineCollection, adapterById, providerById, providerCoversBbox, fetchedSequencesMinZoom, viewConeGeoJson, viewShapeRadiusMeters, setStreetImageryConfig, viewfieldLayerId, photoLayerId, photoTargetLayerId, featureLayerId, PROVIDER_IDS, mapFeatureMatchesDateRange, isBrowserAvailableProvider, photoMatchesFilters, 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, mapFeaturesToFeatureCollection, emptyPointCollection, buildMapFeatureLayerFilter, featureSourceId, photosToFeatureCollection, photosToViewfieldsFeatureCollection, emptyPolygonCollection, buildPhotoLayerFilter, photoSourceId, viewfieldSourceId, sequenceTilesSourceId, renameExpressionProperties, sequenceTilesLayerId, sequenceSourceId, sequenceLayerId, viewfieldLineLayerId, VIEWFIELD_MIN_ZOOM } 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 } from 'react';
|
|
8
|
-
import { useQuery } from '@tanstack/react-query';
|
|
7
|
+
import { lazy, useEffect, Fragment as Fragment$1, Suspense, useState, useRef, useEffectEvent } from 'react';
|
|
8
|
+
import { keepPreviousData, useQuery, useQueries } from '@tanstack/react-query';
|
|
9
|
+
import { create } from 'zustand';
|
|
9
10
|
|
|
10
|
-
var
|
|
11
|
-
var
|
|
11
|
+
var POINTS_SOURCE_ID = "selection-highlight";
|
|
12
|
+
var CONNECTOR_SOURCE_ID = "selection-connector";
|
|
12
13
|
var SEQUENCE_HIGHLIGHT_SOURCE_ID = "sequence-highlight";
|
|
13
|
-
var
|
|
14
|
+
var BASE_COLOR = "#171717";
|
|
15
|
+
var SELECTION_COLOR = "#f97316";
|
|
16
|
+
var SAME_POSITION_METERS = 0.75;
|
|
17
|
+
var ACTIVE_LINE_WIDTH = 2.5;
|
|
14
18
|
var StreetLevelImagerySelectionOverlay = ({
|
|
15
19
|
selectedPhoto,
|
|
16
|
-
selectedSequence
|
|
20
|
+
selectedSequence,
|
|
21
|
+
cameraLngLat,
|
|
22
|
+
sequenceBeforeId,
|
|
23
|
+
beforeId
|
|
17
24
|
}) => {
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
25
|
+
const photoLngLat = selectedPhoto?.lngLat;
|
|
26
|
+
const cameraDiffers = photoLngLat != null && cameraLngLat != null && distanceMeters(photoLngLat, cameraLngLat) > SAME_POSITION_METERS;
|
|
27
|
+
const camera = cameraDiffers ? cameraLngLat : null;
|
|
28
|
+
const dot = photoLngLat && cameraLngLat && !cameraDiffers ? cameraLngLat : photoLngLat;
|
|
29
|
+
const sequenceLines = selectedSequence ? sequencesToFeatureCollection([selectedSequence]) : emptyLineCollection();
|
|
30
|
+
const throughDot = (line) => dot ? alignLineToPoints(line, [dot]) : line;
|
|
31
|
+
const sequenceCollection = {
|
|
32
|
+
...sequenceLines,
|
|
33
|
+
features: sequenceLines.features.map((feature) => ({
|
|
34
|
+
...feature,
|
|
35
|
+
geometry: feature.geometry.type === "LineString" ? { ...feature.geometry, coordinates: throughDot(feature.geometry.coordinates) } : { ...feature.geometry, coordinates: feature.geometry.coordinates.map(throughDot) }
|
|
36
|
+
}))
|
|
37
|
+
};
|
|
38
|
+
if (!selectedPhoto && sequenceCollection.features.length === 0) {
|
|
21
39
|
return null;
|
|
22
40
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Layer,
|
|
41
|
+
const points = {
|
|
42
|
+
type: "FeatureCollection",
|
|
43
|
+
features: [
|
|
44
|
+
...dot ? [
|
|
28
45
|
{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
paint: {
|
|
33
|
-
"circle-radius": 10,
|
|
34
|
-
"circle-color": "#ffffff",
|
|
35
|
-
"circle-stroke-width": 3,
|
|
36
|
-
"circle-stroke-color": "#0f172a"
|
|
37
|
-
}
|
|
46
|
+
type: "Feature",
|
|
47
|
+
properties: { kind: "dot" },
|
|
48
|
+
geometry: { type: "Point", coordinates: dot }
|
|
38
49
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
sequenceHighlightCollection.features.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42
|
-
/* @__PURE__ */ jsx(
|
|
43
|
-
Source,
|
|
50
|
+
] : [],
|
|
51
|
+
...camera ? [
|
|
44
52
|
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
type: "Feature",
|
|
54
|
+
properties: { kind: "camera" },
|
|
55
|
+
geometry: { type: "Point", coordinates: camera }
|
|
48
56
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
] : []
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
const connector = {
|
|
61
|
+
type: "FeatureCollection",
|
|
62
|
+
features: dot && camera ? [
|
|
63
|
+
{
|
|
64
|
+
type: "Feature",
|
|
65
|
+
properties: {},
|
|
66
|
+
geometry: { type: "LineString", coordinates: [dot, camera] }
|
|
67
|
+
}
|
|
68
|
+
] : []
|
|
69
|
+
};
|
|
70
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
71
|
+
/* @__PURE__ */ jsx(Source, { id: SEQUENCE_HIGHLIGHT_SOURCE_ID, type: "geojson", data: sequenceCollection }),
|
|
72
|
+
/* @__PURE__ */ jsx(
|
|
73
|
+
Layer,
|
|
74
|
+
{
|
|
75
|
+
beforeId: sequenceBeforeId ?? beforeId,
|
|
76
|
+
id: "sequence-highlight-layer",
|
|
77
|
+
type: "line",
|
|
78
|
+
source: SEQUENCE_HIGHLIGHT_SOURCE_ID,
|
|
79
|
+
layout: { "line-cap": "round", "line-join": "round" },
|
|
80
|
+
paint: { "line-color": BASE_COLOR, "line-width": ACTIVE_LINE_WIDTH }
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
/* @__PURE__ */ jsx(Source, { id: CONNECTOR_SOURCE_ID, type: "geojson", data: connector }),
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
Layer,
|
|
86
|
+
{
|
|
87
|
+
beforeId,
|
|
88
|
+
id: "selection-connector-layer",
|
|
89
|
+
type: "line",
|
|
90
|
+
source: CONNECTOR_SOURCE_ID,
|
|
91
|
+
paint: { "line-color": SELECTION_COLOR, "line-width": 1.5, "line-dasharray": [2, 1.5] }
|
|
92
|
+
}
|
|
93
|
+
),
|
|
94
|
+
/* @__PURE__ */ jsx(Source, { id: POINTS_SOURCE_ID, type: "geojson", data: points }),
|
|
95
|
+
/* @__PURE__ */ jsx(
|
|
96
|
+
Layer,
|
|
97
|
+
{
|
|
98
|
+
beforeId,
|
|
99
|
+
id: "selection-highlight-layer",
|
|
100
|
+
type: "circle",
|
|
101
|
+
source: POINTS_SOURCE_ID,
|
|
102
|
+
filter: ["==", ["get", "kind"], "dot"],
|
|
103
|
+
paint: {
|
|
104
|
+
"circle-radius": 6,
|
|
105
|
+
"circle-color": SELECTION_COLOR,
|
|
106
|
+
"circle-stroke-width": 2,
|
|
107
|
+
"circle-stroke-color": BASE_COLOR
|
|
61
108
|
}
|
|
62
|
-
|
|
63
|
-
|
|
109
|
+
}
|
|
110
|
+
),
|
|
111
|
+
/* @__PURE__ */ jsx(
|
|
112
|
+
Layer,
|
|
113
|
+
{
|
|
114
|
+
beforeId,
|
|
115
|
+
id: "selection-camera-layer",
|
|
116
|
+
type: "circle",
|
|
117
|
+
source: POINTS_SOURCE_ID,
|
|
118
|
+
filter: ["==", ["get", "kind"], "camera"],
|
|
119
|
+
paint: {
|
|
120
|
+
"circle-radius": 3.5,
|
|
121
|
+
"circle-color": SELECTION_COLOR,
|
|
122
|
+
"circle-stroke-width": 1.5,
|
|
123
|
+
"circle-stroke-color": BASE_COLOR
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
)
|
|
64
127
|
] });
|
|
65
128
|
};
|
|
66
129
|
var resolveSelectedSequence = (selectedPhoto, sequences, sequenceId) => {
|
|
@@ -76,9 +139,11 @@ var withinBbox = (bbox) => (item) => {
|
|
|
76
139
|
const [lng, lat] = item.lngLat;
|
|
77
140
|
return lng >= bbox[0] && lng <= bbox[2] && lat >= bbox[1] && lat <= bbox[3];
|
|
78
141
|
};
|
|
79
|
-
var
|
|
142
|
+
var previousDataWhile = (enabled) => enabled ? keepPreviousData : void 0;
|
|
143
|
+
var useProviderPhotos = (providerId, bbox, zoom, { minZoom = 0 } = {}) => {
|
|
80
144
|
const adapter = adapterById[providerId];
|
|
81
|
-
const
|
|
145
|
+
const meta = providerById[providerId];
|
|
146
|
+
const enabled = meta.kind === "photo" && bbox != null && providerCoversBbox(providerId, bbox) && zoom >= Math.max(meta.minZoom, minZoom) && adapter?.fetchPhotos != null;
|
|
82
147
|
return useQuery({
|
|
83
148
|
queryKey: ["provider-photos", providerId, bboxKey(bbox), zoom],
|
|
84
149
|
queryFn: async ({ signal }) => {
|
|
@@ -86,23 +151,25 @@ var useProviderPhotos = (providerId, bbox, zoom) => {
|
|
|
86
151
|
return photos.filter(withinBbox(bbox));
|
|
87
152
|
},
|
|
88
153
|
enabled,
|
|
89
|
-
placeholderData: (
|
|
154
|
+
placeholderData: previousDataWhile(enabled)
|
|
90
155
|
});
|
|
91
156
|
};
|
|
92
|
-
var useProviderSequences = (providerId, bbox, zoom) => {
|
|
157
|
+
var useProviderSequences = (providerId, bbox, zoom, { minZoom = 0 } = {}) => {
|
|
93
158
|
const adapter = adapterById[providerId];
|
|
94
|
-
const
|
|
95
|
-
const
|
|
159
|
+
const meta = providerById[providerId];
|
|
160
|
+
const sequencesMinZoom = fetchedSequencesMinZoom(providerId);
|
|
161
|
+
const enabled = meta.kind === "photo" && bbox != null && providerCoversBbox(providerId, bbox) && zoom >= Math.max(sequencesMinZoom, minZoom) && adapter?.fetchSequences != null;
|
|
96
162
|
return useQuery({
|
|
97
163
|
queryKey: ["provider-sequences", providerId, bboxKey(bbox), zoom],
|
|
98
|
-
queryFn: ({ signal }) => adapter
|
|
164
|
+
queryFn: ({ signal }) => adapter?.fetchSequences?.(bbox, zoom, signal) ?? [],
|
|
99
165
|
enabled,
|
|
100
|
-
placeholderData: (
|
|
166
|
+
placeholderData: previousDataWhile(enabled)
|
|
101
167
|
});
|
|
102
168
|
};
|
|
103
|
-
var useProviderMapFeatures = (providerId, bbox, zoom) => {
|
|
169
|
+
var useProviderMapFeatures = (providerId, bbox, zoom, { minZoom = 0 } = {}) => {
|
|
104
170
|
const adapter = adapterById[providerId];
|
|
105
|
-
const
|
|
171
|
+
const meta = providerById[providerId];
|
|
172
|
+
const enabled = meta.kind === "mapFeature" && bbox != null && providerCoversBbox(providerId, bbox) && zoom >= Math.max(meta.minZoom, minZoom) && adapter?.fetchMapFeatures != null;
|
|
106
173
|
return useQuery({
|
|
107
174
|
queryKey: ["provider-map-features", providerId, bboxKey(bbox), zoom],
|
|
108
175
|
queryFn: async ({ signal }) => {
|
|
@@ -110,12 +177,13 @@ var useProviderMapFeatures = (providerId, bbox, zoom) => {
|
|
|
110
177
|
return features.filter(withinBbox(bbox));
|
|
111
178
|
},
|
|
112
179
|
enabled,
|
|
113
|
-
placeholderData: (
|
|
180
|
+
placeholderData: previousDataWhile(enabled)
|
|
114
181
|
});
|
|
115
182
|
};
|
|
116
183
|
var CONE_SOURCE_ID = "view-direction-cone";
|
|
117
184
|
var CONE_FILL_LAYER_ID = "view-direction-cone-fill";
|
|
118
|
-
var
|
|
185
|
+
var MIN_CONE_FOV_DEG = 45;
|
|
186
|
+
var VIEW_SHAPE_FILL_OPACITY = 0.25;
|
|
119
187
|
var INTERACTIVE_PANO_PROVIDERS = /* @__PURE__ */ new Set([
|
|
120
188
|
"mapillary",
|
|
121
189
|
"panoramax",
|
|
@@ -127,7 +195,10 @@ var INTERACTIVE_PANO_PROVIDERS = /* @__PURE__ */ new Set([
|
|
|
127
195
|
var StreetLevelImageryViewCone = ({
|
|
128
196
|
selectedPhoto,
|
|
129
197
|
zoom,
|
|
130
|
-
viewerPov
|
|
198
|
+
viewerPov,
|
|
199
|
+
color = SELECTION_COLOR,
|
|
200
|
+
scale = 2.5,
|
|
201
|
+
beforeId
|
|
131
202
|
}) => {
|
|
132
203
|
const apex = viewerPov?.lngLat ?? selectedPhoto.lngLat;
|
|
133
204
|
const isPano = selectedPhoto.isPano === true;
|
|
@@ -140,6 +211,9 @@ var StreetLevelImageryViewCone = ({
|
|
|
140
211
|
} else if (selectedPhoto.providerId === "panoramax") {
|
|
141
212
|
bearing = viewerPov?.bearing ?? selectedPhoto.heading;
|
|
142
213
|
fov = 30;
|
|
214
|
+
} else if (selectedPhoto.providerId === "mapillary") {
|
|
215
|
+
bearing = viewerPov?.bearing ?? selectedPhoto.heading;
|
|
216
|
+
fov = viewerPov?.hfov ?? 30;
|
|
143
217
|
} else {
|
|
144
218
|
bearing = selectedPhoto.heading;
|
|
145
219
|
fov = 30;
|
|
@@ -147,47 +221,29 @@ var StreetLevelImageryViewCone = ({
|
|
|
147
221
|
if (bearing == null) {
|
|
148
222
|
return null;
|
|
149
223
|
}
|
|
150
|
-
|
|
224
|
+
fov = Math.max(fov, MIN_CONE_FOV_DEG);
|
|
225
|
+
const coneFeature = {
|
|
226
|
+
...viewConeGeoJson(apex, bearing, fov, viewShapeRadiusMeters(zoom) * scale),
|
|
227
|
+
properties: { isPano: selectedPhoto.isPano, capturedAt: selectedPhoto.capturedAt }
|
|
228
|
+
};
|
|
151
229
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
152
230
|
/* @__PURE__ */ jsx(Source, { id: CONE_SOURCE_ID, type: "geojson", data: coneFeature }),
|
|
153
231
|
/* @__PURE__ */ jsx(
|
|
154
232
|
Layer,
|
|
155
233
|
{
|
|
234
|
+
beforeId,
|
|
156
235
|
id: CONE_FILL_LAYER_ID,
|
|
157
236
|
type: "fill",
|
|
158
237
|
source: CONE_SOURCE_ID,
|
|
159
238
|
paint: {
|
|
160
|
-
"fill-color":
|
|
161
|
-
"fill-opacity":
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
),
|
|
165
|
-
/* @__PURE__ */ jsx(
|
|
166
|
-
Layer,
|
|
167
|
-
{
|
|
168
|
-
id: CONE_LINE_LAYER_ID,
|
|
169
|
-
type: "line",
|
|
170
|
-
source: CONE_SOURCE_ID,
|
|
171
|
-
paint: {
|
|
172
|
-
"line-color": "#0f172a",
|
|
173
|
-
"line-width": 1.5,
|
|
174
|
-
"line-opacity": 0.5
|
|
239
|
+
"fill-color": color,
|
|
240
|
+
"fill-opacity": VIEW_SHAPE_FILL_OPACITY,
|
|
241
|
+
"fill-outline-color": "rgba(0, 0, 0, 0)"
|
|
175
242
|
}
|
|
176
243
|
}
|
|
177
244
|
)
|
|
178
245
|
] });
|
|
179
246
|
};
|
|
180
|
-
var CIRCLE_RADIUS = [
|
|
181
|
-
"interpolate",
|
|
182
|
-
["linear"],
|
|
183
|
-
["zoom"],
|
|
184
|
-
10,
|
|
185
|
-
2,
|
|
186
|
-
14,
|
|
187
|
-
4,
|
|
188
|
-
18,
|
|
189
|
-
6
|
|
190
|
-
];
|
|
191
247
|
var FEATURE_CIRCLE_RADIUS = [
|
|
192
248
|
"interpolate",
|
|
193
249
|
["linear"],
|
|
@@ -199,6 +255,31 @@ var FEATURE_CIRCLE_RADIUS = [
|
|
|
199
255
|
18,
|
|
200
256
|
4
|
|
201
257
|
];
|
|
258
|
+
var padBbox = ([west, south, east, north], factor) => {
|
|
259
|
+
const dx = (east - west) * factor;
|
|
260
|
+
const dy = (north - south) * factor;
|
|
261
|
+
return [west - dx, south - dy, east + dx, north + dy];
|
|
262
|
+
};
|
|
263
|
+
var lngLatInBbox = ([lng, lat], [west, south, east, north]) => lng >= west && lng <= east && lat >= south && lat <= north;
|
|
264
|
+
var YEAR_MS = 365.25 * 24 * 60 * 60 * 1e3;
|
|
265
|
+
var LOADED_AT = Date.now();
|
|
266
|
+
var AGE_SHADE = [
|
|
267
|
+
"case",
|
|
268
|
+
["==", ["get", "capturedAt"], null],
|
|
269
|
+
BASE_COLOR,
|
|
270
|
+
[
|
|
271
|
+
"step",
|
|
272
|
+
["get", "capturedAt"],
|
|
273
|
+
"#909090",
|
|
274
|
+
LOADED_AT - 3 * YEAR_MS,
|
|
275
|
+
"#686868",
|
|
276
|
+
LOADED_AT - 2 * YEAR_MS,
|
|
277
|
+
"#404040",
|
|
278
|
+
LOADED_AT - YEAR_MS,
|
|
279
|
+
BASE_COLOR
|
|
280
|
+
]
|
|
281
|
+
];
|
|
282
|
+
var PHOTO_TARGET_RADIUS_PX = 10;
|
|
202
283
|
var PHOTO_SORT_KEY = ["coalesce", ["get", "capturedAt"], 0];
|
|
203
284
|
var FEATURE_SORT_KEY = ["coalesce", ["get", "lastSeenAt"], 0];
|
|
204
285
|
var PhotoProviderLayer = ({
|
|
@@ -208,14 +289,62 @@ var PhotoProviderLayer = ({
|
|
|
208
289
|
filter,
|
|
209
290
|
showSequences,
|
|
210
291
|
showViewfields,
|
|
211
|
-
photoCircleColor
|
|
292
|
+
photoCircleColor,
|
|
293
|
+
activeSequenceId,
|
|
294
|
+
hasActiveSequence,
|
|
295
|
+
shownPhotoId,
|
|
296
|
+
beforeId,
|
|
297
|
+
minZoom
|
|
212
298
|
}) => {
|
|
213
299
|
const adapter = adapterById[providerId];
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
const
|
|
300
|
+
const meta = providerById[providerId];
|
|
301
|
+
const photosMinZoom = Math.max(meta.minZoom, minZoom);
|
|
302
|
+
const fetchedLinesMinZoom = fetchedSequencesMinZoom(providerId);
|
|
303
|
+
const sequencesMinZoom = Math.max(fetchedLinesMinZoom, minZoom);
|
|
304
|
+
const { data: photos = [] } = useProviderPhotos(providerId, bbox, zoom, { minZoom });
|
|
305
|
+
const { data: sequences = [] } = useProviderSequences(providerId, bbox, zoom, { minZoom });
|
|
306
|
+
const visiblePhotos = zoom >= photosMinZoom ? photos.filter((photo) => photoMatchesFilters(photo, filter?.photoTypes, filter?.date)) : [];
|
|
307
|
+
const drawBbox = bbox ? padBbox(bbox, 0.25) : null;
|
|
308
|
+
const photoCollection = zoom >= photosMinZoom ? photosToFeatureCollection(
|
|
309
|
+
drawBbox ? visiblePhotos.filter((photo) => lngLatInBbox(photo.lngLat, drawBbox)) : visiblePhotos
|
|
310
|
+
) : emptyPointCollection();
|
|
311
|
+
const viewfieldsActive = showViewfields && zoom >= VIEWFIELD_MIN_ZOOM;
|
|
312
|
+
const viewfieldCollection = viewfieldsActive ? photosToViewfieldsFeatureCollection(visiblePhotos, zoom, { bbox }) : emptyPolygonCollection();
|
|
313
|
+
const inActiveSequence = [
|
|
314
|
+
"==",
|
|
315
|
+
["get", "sequenceId"],
|
|
316
|
+
activeSequenceId ?? ""
|
|
317
|
+
];
|
|
318
|
+
const lineOpacity = [
|
|
319
|
+
"case",
|
|
320
|
+
inActiveSequence,
|
|
321
|
+
1,
|
|
322
|
+
hasActiveSequence ? 0.45 : 1
|
|
323
|
+
];
|
|
324
|
+
const dotRadius = [
|
|
325
|
+
"interpolate",
|
|
326
|
+
["linear"],
|
|
327
|
+
["zoom"],
|
|
328
|
+
10,
|
|
329
|
+
["case", inActiveSequence, 2, 1.2],
|
|
330
|
+
14,
|
|
331
|
+
["case", inActiveSequence, 4, 2],
|
|
332
|
+
// Up to here there are no view shapes and the dots are 20 % smaller.
|
|
333
|
+
VIEWFIELD_MIN_ZOOM - 0.01,
|
|
334
|
+
["case", inActiveSequence, 5.5, 2.9],
|
|
335
|
+
VIEWFIELD_MIN_ZOOM,
|
|
336
|
+
["case", inActiveSequence, 5.5, 3.6],
|
|
337
|
+
18,
|
|
338
|
+
["case", inActiveSequence, 6, 4]
|
|
339
|
+
];
|
|
340
|
+
const lineAndDotColor = viewfieldsActive ? ["case", inActiveSequence, BASE_COLOR, AGE_SHADE] : photoCircleColor;
|
|
341
|
+
const viewShapeOpacity = (full) => [
|
|
342
|
+
"case",
|
|
343
|
+
inActiveSequence,
|
|
344
|
+
full,
|
|
345
|
+
hasActiveSequence ? full * 0.4 : full
|
|
346
|
+
];
|
|
347
|
+
const notShownPhoto = ["!=", ["get", "photoId"], shownPhotoId ?? ""];
|
|
219
348
|
const photoFilter = buildPhotoLayerFilter(filter?.photoTypes, filter?.date);
|
|
220
349
|
const photoSrcId = photoSourceId(providerId);
|
|
221
350
|
const viewfieldSrcId = viewfieldSourceId(providerId);
|
|
@@ -227,7 +356,7 @@ var PhotoProviderLayer = ({
|
|
|
227
356
|
sequenceCapturedAtById.set(photo.sequenceId, photo.capturedAt);
|
|
228
357
|
}
|
|
229
358
|
}
|
|
230
|
-
const filteredSequences = showSequences && zoom >=
|
|
359
|
+
const filteredSequences = showSequences && zoom >= sequencesMinZoom ? sequences.map((sequence) => {
|
|
231
360
|
if (sequence.capturedAt != null) return sequence;
|
|
232
361
|
const fromPhotos = sequenceCapturedAtById.get(sequence.sequenceId);
|
|
233
362
|
return fromPhotos != null ? { ...sequence, capturedAt: fromPhotos } : sequence;
|
|
@@ -243,9 +372,103 @@ var PhotoProviderLayer = ({
|
|
|
243
372
|
};
|
|
244
373
|
return photoMatchesFilters(asPhoto, filter?.photoTypes, filter?.date);
|
|
245
374
|
}) : [];
|
|
246
|
-
const
|
|
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
|
+
const sequenceTiles = showSequences ? adapter?.sequenceTiles?.() : null;
|
|
403
|
+
const sequenceTilesMinZoom = sequenceTiles ? Math.max(sequenceTiles.minZoom, minZoom) : 0;
|
|
404
|
+
const sequenceCollection = alignedSequences.length > 0 ? sequencesToFeatureCollection(alignedSequences) : emptyLineCollection();
|
|
247
405
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
248
|
-
|
|
406
|
+
meta.coverageTiles ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
407
|
+
/* @__PURE__ */ jsx(
|
|
408
|
+
Source,
|
|
409
|
+
{
|
|
410
|
+
id: `coverage-tiles-source-${providerId}`,
|
|
411
|
+
minzoom: meta.coverageTiles.minZoom,
|
|
412
|
+
tileSize: meta.coverageTiles.tileSize,
|
|
413
|
+
tiles: [meta.coverageTiles.url],
|
|
414
|
+
type: "raster"
|
|
415
|
+
}
|
|
416
|
+
),
|
|
417
|
+
/* @__PURE__ */ jsx(
|
|
418
|
+
Layer,
|
|
419
|
+
{
|
|
420
|
+
beforeId,
|
|
421
|
+
id: `coverage-tiles-${providerId}`,
|
|
422
|
+
minzoom: meta.coverageTiles.minZoom,
|
|
423
|
+
paint: { "raster-opacity": 0.7 },
|
|
424
|
+
source: `coverage-tiles-source-${providerId}`,
|
|
425
|
+
type: "raster"
|
|
426
|
+
}
|
|
427
|
+
)
|
|
428
|
+
] }) : null,
|
|
429
|
+
sequenceTiles && sequenceTilesMinZoom < fetchedLinesMinZoom ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
430
|
+
/* @__PURE__ */ jsx(
|
|
431
|
+
Source,
|
|
432
|
+
{
|
|
433
|
+
id: sequenceTilesSourceId(providerId),
|
|
434
|
+
type: "vector",
|
|
435
|
+
tiles: sequenceTiles.tiles,
|
|
436
|
+
minzoom: sequenceTiles.minZoom,
|
|
437
|
+
maxzoom: sequenceTiles.maxZoom
|
|
438
|
+
},
|
|
439
|
+
sequenceTilesSourceId(providerId)
|
|
440
|
+
),
|
|
441
|
+
/* @__PURE__ */ jsx(
|
|
442
|
+
Layer,
|
|
443
|
+
{
|
|
444
|
+
beforeId,
|
|
445
|
+
id: sequenceTilesLayerId(providerId),
|
|
446
|
+
type: "line",
|
|
447
|
+
source: sequenceTilesSourceId(providerId),
|
|
448
|
+
"source-layer": sequenceTiles.sourceLayer,
|
|
449
|
+
minzoom: sequenceTilesMinZoom,
|
|
450
|
+
maxzoom: fetchedLinesMinZoom,
|
|
451
|
+
filter: renameExpressionProperties(photoFilter, sequenceTiles.properties),
|
|
452
|
+
layout: {
|
|
453
|
+
"line-cap": "round",
|
|
454
|
+
"line-join": "round",
|
|
455
|
+
"line-sort-key": renameExpressionProperties(
|
|
456
|
+
["case", inActiveSequence, 1, 0],
|
|
457
|
+
sequenceTiles.properties
|
|
458
|
+
)
|
|
459
|
+
},
|
|
460
|
+
paint: {
|
|
461
|
+
"line-color": renameExpressionProperties(photoCircleColor, sequenceTiles.properties),
|
|
462
|
+
"line-width": renameExpressionProperties(
|
|
463
|
+
["case", inActiveSequence, ACTIVE_LINE_WIDTH, 1.25],
|
|
464
|
+
sequenceTiles.properties
|
|
465
|
+
),
|
|
466
|
+
"line-opacity": renameExpressionProperties(lineOpacity, sequenceTiles.properties)
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
)
|
|
470
|
+
] }) : null,
|
|
471
|
+
adapter?.fetchSequences && showSequences ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
249
472
|
/* @__PURE__ */ jsx(
|
|
250
473
|
Source,
|
|
251
474
|
{
|
|
@@ -258,13 +481,19 @@ var PhotoProviderLayer = ({
|
|
|
258
481
|
/* @__PURE__ */ jsx(
|
|
259
482
|
Layer,
|
|
260
483
|
{
|
|
484
|
+
beforeId,
|
|
261
485
|
id: sequenceLayerId(providerId),
|
|
262
486
|
type: "line",
|
|
263
487
|
source: sequenceSourceId(providerId),
|
|
488
|
+
layout: {
|
|
489
|
+
"line-cap": "round",
|
|
490
|
+
"line-join": "round",
|
|
491
|
+
"line-sort-key": ["case", inActiveSequence, 1, 0]
|
|
492
|
+
},
|
|
264
493
|
paint: {
|
|
265
|
-
"line-color":
|
|
266
|
-
"line-width":
|
|
267
|
-
"line-opacity":
|
|
494
|
+
"line-color": lineAndDotColor,
|
|
495
|
+
"line-width": ["case", inActiveSequence, ACTIVE_LINE_WIDTH, 1.25],
|
|
496
|
+
"line-opacity": lineOpacity
|
|
268
497
|
}
|
|
269
498
|
}
|
|
270
499
|
)
|
|
@@ -282,25 +511,30 @@ var PhotoProviderLayer = ({
|
|
|
282
511
|
/* @__PURE__ */ jsx(
|
|
283
512
|
Layer,
|
|
284
513
|
{
|
|
514
|
+
beforeId,
|
|
285
515
|
id: viewfieldLayerId(providerId),
|
|
286
516
|
type: "fill",
|
|
287
517
|
source: viewfieldSrcId,
|
|
518
|
+
filter: notShownPhoto,
|
|
288
519
|
paint: {
|
|
289
520
|
"fill-color": photoCircleColor,
|
|
290
|
-
"fill-opacity":
|
|
521
|
+
"fill-opacity": viewShapeOpacity(VIEW_SHAPE_FILL_OPACITY),
|
|
522
|
+
"fill-outline-color": "rgba(0, 0, 0, 0)"
|
|
291
523
|
}
|
|
292
524
|
}
|
|
293
525
|
),
|
|
294
526
|
/* @__PURE__ */ jsx(
|
|
295
527
|
Layer,
|
|
296
528
|
{
|
|
529
|
+
beforeId,
|
|
297
530
|
id: viewfieldLineLayerId(providerId),
|
|
298
531
|
type: "line",
|
|
299
532
|
source: viewfieldSrcId,
|
|
533
|
+
filter: notShownPhoto,
|
|
300
534
|
paint: {
|
|
301
535
|
"line-color": photoCircleColor,
|
|
302
|
-
"line-width":
|
|
303
|
-
"line-opacity": 0.
|
|
536
|
+
"line-width": 0.5,
|
|
537
|
+
"line-opacity": viewShapeOpacity(0.3)
|
|
304
538
|
}
|
|
305
539
|
}
|
|
306
540
|
)
|
|
@@ -318,16 +552,27 @@ var PhotoProviderLayer = ({
|
|
|
318
552
|
/* @__PURE__ */ jsx(
|
|
319
553
|
Layer,
|
|
320
554
|
{
|
|
555
|
+
beforeId,
|
|
556
|
+
id: photoTargetLayerId(providerId),
|
|
557
|
+
type: "circle",
|
|
558
|
+
source: photoSrcId,
|
|
559
|
+
filter: photoFilter,
|
|
560
|
+
layout: { "circle-sort-key": PHOTO_SORT_KEY },
|
|
561
|
+
paint: { "circle-radius": PHOTO_TARGET_RADIUS_PX, "circle-opacity": 0 }
|
|
562
|
+
}
|
|
563
|
+
),
|
|
564
|
+
/* @__PURE__ */ jsx(
|
|
565
|
+
Layer,
|
|
566
|
+
{
|
|
567
|
+
beforeId,
|
|
321
568
|
id: photoLayerId(providerId),
|
|
322
569
|
type: "circle",
|
|
323
570
|
source: photoSrcId,
|
|
324
571
|
filter: photoFilter,
|
|
325
572
|
layout: { "circle-sort-key": PHOTO_SORT_KEY },
|
|
326
573
|
paint: {
|
|
327
|
-
"circle-radius":
|
|
328
|
-
"circle-color":
|
|
329
|
-
"circle-stroke-width": 1,
|
|
330
|
-
"circle-stroke-color": "#ffffff"
|
|
574
|
+
"circle-radius": dotRadius,
|
|
575
|
+
"circle-color": lineAndDotColor
|
|
331
576
|
}
|
|
332
577
|
}
|
|
333
578
|
)
|
|
@@ -338,11 +583,16 @@ var MapFeatureProviderLayer = ({
|
|
|
338
583
|
bbox,
|
|
339
584
|
zoom,
|
|
340
585
|
filter,
|
|
341
|
-
mapFeatureCircleColor
|
|
586
|
+
mapFeatureCircleColor,
|
|
587
|
+
beforeId,
|
|
588
|
+
minZoom
|
|
342
589
|
}) => {
|
|
343
|
-
const
|
|
344
|
-
const { data: features = [] } = useProviderMapFeatures(providerId, bbox, zoom);
|
|
345
|
-
const
|
|
590
|
+
const meta = providerById[providerId];
|
|
591
|
+
const { data: features = [] } = useProviderMapFeatures(providerId, bbox, zoom, { minZoom });
|
|
592
|
+
const valueFilter = filter?.mapFeatureValue;
|
|
593
|
+
const featureCollection = zoom >= Math.max(meta.minZoom, minZoom) ? mapFeaturesToFeatureCollection(
|
|
594
|
+
valueFilter ? features.filter((feature) => valueFilter(feature.value)) : features
|
|
595
|
+
) : emptyPointCollection();
|
|
346
596
|
const featureFilter = buildMapFeatureLayerFilter(filter?.date);
|
|
347
597
|
const featureSrcId = featureSourceId(providerId);
|
|
348
598
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -359,6 +609,7 @@ var MapFeatureProviderLayer = ({
|
|
|
359
609
|
/* @__PURE__ */ jsx(
|
|
360
610
|
Layer,
|
|
361
611
|
{
|
|
612
|
+
beforeId,
|
|
362
613
|
id: featureLayerId(providerId),
|
|
363
614
|
type: "circle",
|
|
364
615
|
source: featureSrcId,
|
|
@@ -366,17 +617,14 @@ var MapFeatureProviderLayer = ({
|
|
|
366
617
|
layout: { "circle-sort-key": FEATURE_SORT_KEY },
|
|
367
618
|
paint: {
|
|
368
619
|
"circle-radius": FEATURE_CIRCLE_RADIUS,
|
|
369
|
-
"circle-color": mapFeatureCircleColor
|
|
370
|
-
"circle-stroke-width": 1,
|
|
371
|
-
"circle-stroke-color": "#ffffff"
|
|
620
|
+
"circle-color": mapFeatureCircleColor
|
|
372
621
|
}
|
|
373
622
|
}
|
|
374
623
|
)
|
|
375
624
|
] });
|
|
376
625
|
};
|
|
377
626
|
var ProviderLayer = (props) => {
|
|
378
|
-
|
|
379
|
-
return adapter.kind === "mapFeature" ? /* @__PURE__ */ jsx(MapFeatureProviderLayer, { ...props }) : /* @__PURE__ */ jsx(PhotoProviderLayer, { ...props });
|
|
627
|
+
return providerById[props.providerId].kind === "mapFeature" ? /* @__PURE__ */ jsx(MapFeatureProviderLayer, { ...props }) : /* @__PURE__ */ jsx(PhotoProviderLayer, { ...props });
|
|
380
628
|
};
|
|
381
629
|
var StreetLevelImagerySourcesAndLayers = ({
|
|
382
630
|
providers,
|
|
@@ -394,8 +642,12 @@ var StreetLevelImagerySourcesAndLayers = ({
|
|
|
394
642
|
selectedPhoto,
|
|
395
643
|
selectedSequenceId,
|
|
396
644
|
viewerPov,
|
|
645
|
+
viewConeColor,
|
|
646
|
+
viewConeScale,
|
|
397
647
|
photoCircleColor,
|
|
398
|
-
mapFeatureCircleColor
|
|
648
|
+
mapFeatureCircleColor,
|
|
649
|
+
beforeId,
|
|
650
|
+
minZoom = 0
|
|
399
651
|
} = options;
|
|
400
652
|
useEffect(
|
|
401
653
|
function applyStreetImageryConfig() {
|
|
@@ -411,18 +663,25 @@ var StreetLevelImagerySourcesAndLayers = ({
|
|
|
411
663
|
showSelectionHighlight && selectedProviderId ? bbox : null,
|
|
412
664
|
zoom
|
|
413
665
|
);
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
666
|
+
const activeSequenceId = selectedSequenceId ?? selectedPhoto?.sequenceId;
|
|
667
|
+
const selectedSequence = resolveSelectedSequence(selectedPhoto, sequences, activeSequenceId);
|
|
668
|
+
const providerDrawsSequences = selectedProviderId != null && showSequences && providers.includes(selectedProviderId);
|
|
669
|
+
const firstPhotoProvider = providers.find(
|
|
670
|
+
(id) => providerById[id].kind === "photo" && adapterById[id]?.fetchPhotos
|
|
418
671
|
);
|
|
672
|
+
const sequenceBeforeId = firstPhotoProvider ? showViewfields ? viewfieldLayerId(firstPhotoProvider) : photoLayerId(firstPhotoProvider) : void 0;
|
|
419
673
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
420
674
|
providers.map((providerId) => /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(
|
|
421
675
|
ProviderLayer,
|
|
422
676
|
{
|
|
677
|
+
beforeId,
|
|
678
|
+
minZoom,
|
|
423
679
|
bbox,
|
|
424
680
|
filter,
|
|
425
681
|
mapFeatureCircleColor,
|
|
682
|
+
activeSequenceId: providerId === selectedProviderId ? activeSequenceId : null,
|
|
683
|
+
hasActiveSequence: activeSequenceId != null,
|
|
684
|
+
shownPhotoId: showViewCone && providerId === selectedProviderId ? selectedPhoto?.photoId : null,
|
|
426
685
|
photoCircleColor,
|
|
427
686
|
providerId,
|
|
428
687
|
showSequences,
|
|
@@ -433,6 +692,9 @@ var StreetLevelImagerySourcesAndLayers = ({
|
|
|
433
692
|
showViewCone && selectedPhoto ? /* @__PURE__ */ jsx(
|
|
434
693
|
StreetLevelImageryViewCone,
|
|
435
694
|
{
|
|
695
|
+
beforeId,
|
|
696
|
+
color: viewConeColor ?? SELECTION_COLOR,
|
|
697
|
+
scale: viewConeScale,
|
|
436
698
|
selectedPhoto,
|
|
437
699
|
viewerPov,
|
|
438
700
|
zoom
|
|
@@ -441,45 +703,65 @@ var StreetLevelImagerySourcesAndLayers = ({
|
|
|
441
703
|
showSelectionHighlight ? /* @__PURE__ */ jsx(
|
|
442
704
|
StreetLevelImagerySelectionOverlay,
|
|
443
705
|
{
|
|
706
|
+
beforeId,
|
|
707
|
+
cameraLngLat: viewerPov?.lngLat,
|
|
444
708
|
selectedPhoto,
|
|
445
|
-
selectedSequence
|
|
709
|
+
selectedSequence: providerDrawsSequences ? null : selectedSequence,
|
|
710
|
+
sequenceBeforeId
|
|
446
711
|
}
|
|
447
712
|
) : null
|
|
448
713
|
] });
|
|
449
714
|
};
|
|
450
|
-
var
|
|
451
|
-
() => import('./MapillaryPanel-
|
|
715
|
+
var MapillaryPanel = lazy(
|
|
716
|
+
() => import('./MapillaryPanel-FAXVZH37.js').then((module) => ({
|
|
452
717
|
default: module.MapillaryPanel
|
|
453
718
|
}))
|
|
454
719
|
);
|
|
455
|
-
var
|
|
456
|
-
() => import('./PanoramaxPanel-
|
|
720
|
+
var PanoramaxPanel = lazy(
|
|
721
|
+
() => import('./PanoramaxPanel-TWKTSOXM.js').then((module) => ({
|
|
457
722
|
default: module.PanoramaxPanel
|
|
458
723
|
}))
|
|
459
724
|
);
|
|
460
|
-
var ViewerPanelPlaceholder = () =>
|
|
725
|
+
var ViewerPanelPlaceholder = () => {
|
|
726
|
+
const { messages } = useStreetImageryI18n();
|
|
727
|
+
return /* @__PURE__ */ jsx("div", { className: "flex min-h-48 animate-pulse items-center justify-center rounded-lg border border-slate-200 bg-slate-100", children: /* @__PURE__ */ jsx("span", { className: "text-sm text-slate-500", children: messages.viewer.loading }) });
|
|
728
|
+
};
|
|
461
729
|
var StreetLevelImageryViewer = ({
|
|
462
730
|
photo,
|
|
463
731
|
groupPhotos,
|
|
464
732
|
onPhotoSelected,
|
|
465
|
-
onEaseMapToPoint
|
|
733
|
+
onEaseMapToPoint,
|
|
734
|
+
onViewerPhoto,
|
|
735
|
+
lookAtBearing,
|
|
736
|
+
lookAt,
|
|
737
|
+
outlines,
|
|
738
|
+
hideAttribution,
|
|
739
|
+
panoramaxPanel: PanoramaxPanelOverride
|
|
466
740
|
}) => {
|
|
467
741
|
if (photo.providerId === "mapillary") {
|
|
468
742
|
return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerPanelPlaceholder, {}), children: /* @__PURE__ */ jsx(
|
|
469
|
-
|
|
743
|
+
MapillaryPanel,
|
|
470
744
|
{
|
|
471
745
|
groupPhotos,
|
|
746
|
+
hideAttribution,
|
|
472
747
|
onEaseMapToPoint,
|
|
473
748
|
onPhotoSelected,
|
|
749
|
+
lookAt,
|
|
750
|
+
lookAtBearing,
|
|
751
|
+
outlines,
|
|
752
|
+
onViewerPhoto,
|
|
474
753
|
photo
|
|
475
754
|
}
|
|
476
755
|
) });
|
|
477
756
|
}
|
|
478
757
|
if (photo.providerId === "panoramax") {
|
|
758
|
+
const Panel = PanoramaxPanelOverride ?? PanoramaxPanel;
|
|
479
759
|
return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerPanelPlaceholder, {}), children: /* @__PURE__ */ jsx(
|
|
480
|
-
|
|
760
|
+
Panel,
|
|
481
761
|
{
|
|
482
762
|
groupPhotos,
|
|
763
|
+
hideAttribution,
|
|
764
|
+
onViewerPhoto,
|
|
483
765
|
onEaseMapToPoint,
|
|
484
766
|
onPhotoSelected,
|
|
485
767
|
photo
|
|
@@ -490,6 +772,7 @@ var StreetLevelImageryViewer = ({
|
|
|
490
772
|
};
|
|
491
773
|
var streetImageryInteractiveLayerIds = (providers) => [
|
|
492
774
|
...providers.map((providerId) => photoLayerId(providerId)),
|
|
775
|
+
...providers.map((providerId) => photoTargetLayerId(providerId)),
|
|
493
776
|
...providers.map((providerId) => viewfieldLayerId(providerId)),
|
|
494
777
|
...providers.map((providerId) => featureLayerId(providerId))
|
|
495
778
|
];
|
|
@@ -498,6 +781,10 @@ var parseProviderIdFromLayerId = (layerId) => {
|
|
|
498
781
|
if (photoMatch) {
|
|
499
782
|
return photoMatch[1];
|
|
500
783
|
}
|
|
784
|
+
const targetMatch = layerId.match(/^photo-targets-(.+)$/);
|
|
785
|
+
if (targetMatch) {
|
|
786
|
+
return targetMatch[1];
|
|
787
|
+
}
|
|
501
788
|
const viewfieldMatch = layerId.match(/^viewfields-(.+)$/);
|
|
502
789
|
if (viewfieldMatch) {
|
|
503
790
|
return viewfieldMatch[1];
|
|
@@ -522,7 +809,7 @@ var queryStreetImageryFeatures = (event) => {
|
|
|
522
809
|
continue;
|
|
523
810
|
}
|
|
524
811
|
const props = feature.properties ?? {};
|
|
525
|
-
if (layerId.startsWith("photos-") || layerId.startsWith("viewfields-")) {
|
|
812
|
+
if (layerId.startsWith("photos-") || layerId.startsWith("photo-targets-") || layerId.startsWith("viewfields-")) {
|
|
526
813
|
const photoId = props.photoId;
|
|
527
814
|
if (photoId == null) {
|
|
528
815
|
continue;
|
|
@@ -567,18 +854,6 @@ var useAllProviderMapFeatures = (providerIds, bbox, zoom, date) => {
|
|
|
567
854
|
return data.filter((feature) => mapFeatureMatchesDateRange(feature, date));
|
|
568
855
|
});
|
|
569
856
|
};
|
|
570
|
-
var useAllProviderMapFeaturesLoading = (providerIds, bbox, zoom) => {
|
|
571
|
-
const enabled = new Set(providerIds);
|
|
572
|
-
const queries = PROVIDER_IDS.map((providerId) => ({
|
|
573
|
-
providerId,
|
|
574
|
-
query: useProviderMapFeaturesMaybe(providerId, enabled.has(providerId), bbox, zoom)
|
|
575
|
-
}));
|
|
576
|
-
const activeQueries = queries.filter(({ providerId }) => enabled.has(providerId));
|
|
577
|
-
return {
|
|
578
|
-
isLoading: activeQueries.some(({ query }) => query.isLoading),
|
|
579
|
-
isFetching: activeQueries.some(({ query }) => query.isFetching)
|
|
580
|
-
};
|
|
581
|
-
};
|
|
582
857
|
var useProviderPhotosMaybe = (providerId, enabled, bbox, zoom) => useProviderPhotos(providerId, enabled ? bbox : null, zoom);
|
|
583
858
|
var useAllProviderPhotos = (providerIds, bbox, zoom, photoTypes, date) => {
|
|
584
859
|
const enabled = new Set(providerIds);
|
|
@@ -655,5 +930,1132 @@ var usePhotoThumbnail = (photo) => useQuery({
|
|
|
655
930
|
enabled: photo != null,
|
|
656
931
|
staleTime: 24 * 60 * 60 * 1e3
|
|
657
932
|
});
|
|
933
|
+
var PhotoCount = ({ index, total, className }) => /* @__PURE__ */ jsxs("span", { className: `inline-flex shrink-0 items-center gap-0.5 tabular-nums ${className ?? ""}`, children: [
|
|
934
|
+
/* @__PURE__ */ jsx(
|
|
935
|
+
"svg",
|
|
936
|
+
{
|
|
937
|
+
"aria-hidden": true,
|
|
938
|
+
className: "size-3 shrink-0",
|
|
939
|
+
fill: "none",
|
|
940
|
+
stroke: "currentColor",
|
|
941
|
+
strokeLinecap: "round",
|
|
942
|
+
strokeLinejoin: "round",
|
|
943
|
+
strokeWidth: 1.75,
|
|
944
|
+
viewBox: "0 0 24 24",
|
|
945
|
+
children: /* @__PURE__ */ jsx("path", { d: "M4 6h16v12H4ZM4 15l4.5-4.5 4 4L15 12l5 5M9 9.5h.01" })
|
|
946
|
+
}
|
|
947
|
+
),
|
|
948
|
+
index != null ? `${index}/` : "",
|
|
949
|
+
total
|
|
950
|
+
] });
|
|
951
|
+
var PhotoDate = ({ timestamp, className, localDateTime }) => {
|
|
952
|
+
const { locale, messages } = useStreetImageryI18n();
|
|
953
|
+
if (timestamp == null) {
|
|
954
|
+
return /* @__PURE__ */ jsx("span", { className, children: messages.unknownDate });
|
|
955
|
+
}
|
|
956
|
+
const precise = localDateTime ? formatLocalDateTime(localDateTime, locale) : null;
|
|
957
|
+
return /* @__PURE__ */ jsx(
|
|
958
|
+
"time",
|
|
959
|
+
{
|
|
960
|
+
className,
|
|
961
|
+
dateTime: new Date(timestamp).toISOString(),
|
|
962
|
+
title: precise ? `${precise}
|
|
963
|
+
${formatRelativeDate(timestamp, locale)}` : formatDateTooltip(timestamp, locale),
|
|
964
|
+
children: formatMonth(timestamp, locale)
|
|
965
|
+
}
|
|
966
|
+
);
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
// src/viewpoints/viewDirectionLabels.ts
|
|
970
|
+
var viewSuggestionLabel = ({ viewpoint, direction }, messages) => messages.viewDirection(viewpoint.label ?? messages.viewpointRole[viewpoint.role], direction.kind);
|
|
971
|
+
var DEFAULT_LAYOUT = { right: 16, bottom: 32, width: 420, minimized: false };
|
|
972
|
+
var MIN_WIDTH = 280;
|
|
973
|
+
var EDGE = 8;
|
|
974
|
+
var hasStoredLayout = (storageKey) => {
|
|
975
|
+
try {
|
|
976
|
+
return localStorage.getItem(storageKey) != null;
|
|
977
|
+
} catch {
|
|
978
|
+
return false;
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
var readLayout = (storageKey) => {
|
|
982
|
+
try {
|
|
983
|
+
const raw = localStorage.getItem(storageKey);
|
|
984
|
+
return raw ? { ...DEFAULT_LAYOUT, ...JSON.parse(raw) } : DEFAULT_LAYOUT;
|
|
985
|
+
} catch {
|
|
986
|
+
return DEFAULT_LAYOUT;
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
var writeLayout = (storageKey, layout) => {
|
|
990
|
+
try {
|
|
991
|
+
localStorage.setItem(storageKey, JSON.stringify(layout));
|
|
992
|
+
} catch {
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
var Icon = ({ path, className = "size-4" }) => /* @__PURE__ */ jsx(
|
|
996
|
+
"svg",
|
|
997
|
+
{
|
|
998
|
+
"aria-hidden": true,
|
|
999
|
+
className,
|
|
1000
|
+
fill: "none",
|
|
1001
|
+
stroke: "currentColor",
|
|
1002
|
+
strokeLinecap: "round",
|
|
1003
|
+
strokeLinejoin: "round",
|
|
1004
|
+
strokeWidth: 1.75,
|
|
1005
|
+
viewBox: "0 0 24 24",
|
|
1006
|
+
children: /* @__PURE__ */ jsx("path", { d: path })
|
|
1007
|
+
}
|
|
1008
|
+
);
|
|
1009
|
+
var ICONS = {
|
|
1010
|
+
back: "M15 18l-6-6 6-6",
|
|
1011
|
+
undo: "M9 14 4 9l5-5M4 9h10.5a5.5 5.5 0 0 1 0 11H11",
|
|
1012
|
+
redo: "m15 14 5-5-5-5M20 9H9.5a5.5 5.5 0 0 0 0 11H13",
|
|
1013
|
+
forward: "M9 18l6-6-6-6",
|
|
1014
|
+
close: "M18 6 6 18M6 6l12 12",
|
|
1015
|
+
minimize: "M5 12h14",
|
|
1016
|
+
expand: "M4 14v6h6M20 10V4h-6M14 10l6-6M10 14l-6 6",
|
|
1017
|
+
arrow: "M12 20V5M6 11l6-6 6 6",
|
|
1018
|
+
info: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18ZM12 11v5M12 8h.01"
|
|
1019
|
+
};
|
|
1020
|
+
var ToolbarButton = ({
|
|
1021
|
+
label,
|
|
1022
|
+
onClick,
|
|
1023
|
+
disabled,
|
|
1024
|
+
children
|
|
1025
|
+
}) => /* @__PURE__ */ jsx(
|
|
1026
|
+
"button",
|
|
1027
|
+
{
|
|
1028
|
+
"aria-label": label,
|
|
1029
|
+
className: "inline-flex size-7 items-center justify-center rounded-md text-slate-600 hover:bg-slate-100 hover:text-slate-900 disabled:cursor-not-allowed disabled:opacity-30 disabled:hover:bg-transparent",
|
|
1030
|
+
disabled,
|
|
1031
|
+
onClick,
|
|
1032
|
+
title: label,
|
|
1033
|
+
type: "button",
|
|
1034
|
+
children
|
|
1035
|
+
}
|
|
1036
|
+
);
|
|
1037
|
+
var SuggestionChip = ({
|
|
1038
|
+
suggestion,
|
|
1039
|
+
active,
|
|
1040
|
+
shownPhotoId,
|
|
1041
|
+
showPlace,
|
|
1042
|
+
onSelect
|
|
1043
|
+
}) => {
|
|
1044
|
+
const { messages } = useStreetImageryI18n();
|
|
1045
|
+
const { candidates } = suggestion;
|
|
1046
|
+
const best = candidates[0];
|
|
1047
|
+
const shownIndex = active ? candidates.findIndex((candidate) => candidate.photo.photoId === shownPhotoId) : -1;
|
|
1048
|
+
const shown = shownIndex >= 0 ? candidates[shownIndex] : best;
|
|
1049
|
+
const canStep = active && candidates.length > 1;
|
|
1050
|
+
const hasCount = candidates.length > 0;
|
|
1051
|
+
const name = viewSuggestionLabel(suggestion, messages);
|
|
1052
|
+
const label = canStep ? messages.viewer.nextPhotoOfView(name) : name;
|
|
1053
|
+
return /* @__PURE__ */ jsxs(
|
|
1054
|
+
"button",
|
|
1055
|
+
{
|
|
1056
|
+
"aria-label": best ? label : messages.viewer.noPhoto(label),
|
|
1057
|
+
"aria-pressed": active,
|
|
1058
|
+
className: [
|
|
1059
|
+
"flex min-w-0 flex-col items-center rounded-md border px-1 py-0.5 text-xs leading-tight",
|
|
1060
|
+
active ? "border-fuchsia-600 bg-fuchsia-600 text-white" : best ? "border-slate-300 bg-white text-slate-700 hover:border-fuchsia-500" : "border-dashed border-slate-200 bg-white text-slate-400"
|
|
1061
|
+
].join(" "),
|
|
1062
|
+
disabled: !best,
|
|
1063
|
+
onClick: () => {
|
|
1064
|
+
const next = canStep ? candidates[(shownIndex + 1) % candidates.length] : best;
|
|
1065
|
+
if (next) {
|
|
1066
|
+
onSelect(next);
|
|
1067
|
+
}
|
|
1068
|
+
},
|
|
1069
|
+
title: best ? label : messages.viewer.noMatchingPhoto(label),
|
|
1070
|
+
type: "button",
|
|
1071
|
+
children: [
|
|
1072
|
+
/* @__PURE__ */ jsxs(
|
|
1073
|
+
"span",
|
|
1074
|
+
{
|
|
1075
|
+
className: `flex items-center gap-1 font-medium ${hasCount ? "w-full justify-between px-1" : "max-w-full"}`,
|
|
1076
|
+
children: [
|
|
1077
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-1", children: [
|
|
1078
|
+
/* @__PURE__ */ jsx(
|
|
1079
|
+
"span",
|
|
1080
|
+
{
|
|
1081
|
+
"aria-hidden": true,
|
|
1082
|
+
className: "inline-flex shrink-0",
|
|
1083
|
+
style: { transform: `rotate(${suggestion.direction.bearing}deg)` },
|
|
1084
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-3", path: ICONS.arrow })
|
|
1085
|
+
}
|
|
1086
|
+
),
|
|
1087
|
+
/* @__PURE__ */ jsxs("span", { className: "truncate", children: [
|
|
1088
|
+
showPlace ? `${suggestion.viewpoint.label ?? messages.viewpointRole[suggestion.viewpoint.role]} ` : "",
|
|
1089
|
+
messages.compass[Math.round(suggestion.direction.bearing / 45) % 8]
|
|
1090
|
+
] })
|
|
1091
|
+
] }),
|
|
1092
|
+
hasCount ? /* @__PURE__ */ jsx(
|
|
1093
|
+
PhotoCount,
|
|
1094
|
+
{
|
|
1095
|
+
className: `font-normal ${active ? "text-fuchsia-100" : "text-slate-500"}`,
|
|
1096
|
+
index: shownIndex >= 0 ? shownIndex + 1 : void 0,
|
|
1097
|
+
total: candidates.length
|
|
1098
|
+
}
|
|
1099
|
+
) : null
|
|
1100
|
+
]
|
|
1101
|
+
}
|
|
1102
|
+
),
|
|
1103
|
+
shown ? /* @__PURE__ */ jsx(
|
|
1104
|
+
PhotoDate,
|
|
1105
|
+
{
|
|
1106
|
+
className: `max-w-full truncate ${active ? "text-fuchsia-100" : "text-slate-400"}`,
|
|
1107
|
+
timestamp: shown.photo.capturedAt
|
|
1108
|
+
}
|
|
1109
|
+
) : /* @__PURE__ */ jsx("span", { className: "text-slate-400", children: "\u2014" })
|
|
1110
|
+
]
|
|
1111
|
+
}
|
|
1112
|
+
);
|
|
1113
|
+
};
|
|
1114
|
+
var FloatingViewerInfoButton = ({
|
|
1115
|
+
label,
|
|
1116
|
+
onClick
|
|
1117
|
+
}) => /* @__PURE__ */ jsx(ToolbarButton, { label, onClick, children: /* @__PURE__ */ jsx(Icon, { path: ICONS.info }) });
|
|
1118
|
+
var FloatingPhotoViewer = ({
|
|
1119
|
+
title,
|
|
1120
|
+
titleActions,
|
|
1121
|
+
suggestions,
|
|
1122
|
+
activeDirectionKey,
|
|
1123
|
+
onSelectSuggestion,
|
|
1124
|
+
shownPhotoId,
|
|
1125
|
+
canGoBack = false,
|
|
1126
|
+
canGoForward = false,
|
|
1127
|
+
onBack,
|
|
1128
|
+
onForward,
|
|
1129
|
+
onClose,
|
|
1130
|
+
step,
|
|
1131
|
+
toolbar,
|
|
1132
|
+
status,
|
|
1133
|
+
children,
|
|
1134
|
+
footer,
|
|
1135
|
+
drawer,
|
|
1136
|
+
storageKey = "street-imagery:floating-viewer",
|
|
1137
|
+
defaultPosition
|
|
1138
|
+
}) => {
|
|
1139
|
+
const { messages } = useStreetImageryI18n();
|
|
1140
|
+
const severalViewpoints = new Set(suggestions.map((suggestion) => suggestion.viewpoint.id)).size > 1;
|
|
1141
|
+
const [layout, setLayout] = useState(() => readLayout(storageKey));
|
|
1142
|
+
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
1143
|
+
const [moved, setMoved] = useState(() => hasStoredLayout(storageKey));
|
|
1144
|
+
const atTopLeft = defaultPosition?.corner === "top-left" && !moved;
|
|
1145
|
+
const position = atTopLeft ? { left: defaultPosition.left ?? EDGE, top: defaultPosition.top ?? EDGE } : { right: layout.right, bottom: layout.bottom };
|
|
1146
|
+
const dragRef = useRef(null);
|
|
1147
|
+
const updateLayout = (next) => {
|
|
1148
|
+
setLayout(next);
|
|
1149
|
+
writeLayout(storageKey, next);
|
|
1150
|
+
};
|
|
1151
|
+
const onShortcut = useEffectEvent((event) => {
|
|
1152
|
+
const target = event.target;
|
|
1153
|
+
if (target instanceof Element && target.closest('input, textarea, select, [contenteditable="true"]')) {
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
if (event.key === "Escape") {
|
|
1157
|
+
onClose();
|
|
1158
|
+
} else if (event.key === "[" && canGoBack) {
|
|
1159
|
+
onBack?.();
|
|
1160
|
+
} else if (event.key === "]" && canGoForward) {
|
|
1161
|
+
onForward?.();
|
|
1162
|
+
} else if (event.key === "ArrowLeft" && event.altKey) {
|
|
1163
|
+
step?.onPrevious?.();
|
|
1164
|
+
} else if (event.key === "ArrowRight" && event.altKey) {
|
|
1165
|
+
step?.onNext?.();
|
|
1166
|
+
}
|
|
1167
|
+
});
|
|
1168
|
+
useEffect(function subscribeKeyboardShortcuts() {
|
|
1169
|
+
window.addEventListener("keydown", onShortcut);
|
|
1170
|
+
return () => window.removeEventListener("keydown", onShortcut);
|
|
1171
|
+
}, []);
|
|
1172
|
+
const startDrag = (event, mode) => {
|
|
1173
|
+
if (event.button !== 0 || event.target.closest("button")) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
1177
|
+
const box = event.currentTarget.closest("section");
|
|
1178
|
+
const container = box?.offsetParent;
|
|
1179
|
+
const start = atTopLeft && box && container ? {
|
|
1180
|
+
...layout,
|
|
1181
|
+
right: container.clientWidth - box.offsetLeft - box.offsetWidth,
|
|
1182
|
+
bottom: container.clientHeight - box.offsetTop - box.offsetHeight
|
|
1183
|
+
} : layout;
|
|
1184
|
+
setLayout(start);
|
|
1185
|
+
setMoved(true);
|
|
1186
|
+
dragRef.current = { x: event.clientX, y: event.clientY, layout: start, mode };
|
|
1187
|
+
};
|
|
1188
|
+
const onDrag = (event) => {
|
|
1189
|
+
const drag = dragRef.current;
|
|
1190
|
+
if (!drag) {
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
const dx = event.clientX - drag.x;
|
|
1194
|
+
const dy = event.clientY - drag.y;
|
|
1195
|
+
setLayout(
|
|
1196
|
+
drag.mode === "move" ? {
|
|
1197
|
+
...drag.layout,
|
|
1198
|
+
right: Math.max(EDGE, drag.layout.right - dx),
|
|
1199
|
+
bottom: Math.max(EDGE, drag.layout.bottom - dy)
|
|
1200
|
+
} : { ...drag.layout, width: Math.max(MIN_WIDTH, drag.layout.width - dx) }
|
|
1201
|
+
);
|
|
1202
|
+
};
|
|
1203
|
+
const endDrag = () => {
|
|
1204
|
+
if (dragRef.current) {
|
|
1205
|
+
dragRef.current = null;
|
|
1206
|
+
writeLayout(storageKey, layout);
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
const dragHandlers = { onPointerMove: onDrag, onPointerUp: endDrag, onPointerCancel: endDrag };
|
|
1210
|
+
if (layout.minimized) {
|
|
1211
|
+
return /* @__PURE__ */ jsxs(
|
|
1212
|
+
"button",
|
|
1213
|
+
{
|
|
1214
|
+
className: "absolute z-10 inline-flex items-center gap-2 rounded-full bg-white px-3 py-1.5 text-sm font-medium text-slate-800 shadow-lg ring-1 ring-slate-200 hover:bg-slate-50",
|
|
1215
|
+
onClick: () => updateLayout({ ...layout, minimized: false }),
|
|
1216
|
+
style: position,
|
|
1217
|
+
type: "button",
|
|
1218
|
+
children: [
|
|
1219
|
+
/* @__PURE__ */ jsx(Icon, { path: ICONS.expand }),
|
|
1220
|
+
title
|
|
1221
|
+
]
|
|
1222
|
+
}
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
return /* @__PURE__ */ jsxs(
|
|
1226
|
+
"section",
|
|
1227
|
+
{
|
|
1228
|
+
"aria-label": messages.viewer.regionLabel,
|
|
1229
|
+
className: "absolute z-10 flex max-h-[calc(100%-1rem)] flex-col overflow-hidden rounded-xl bg-white shadow-xl ring-1 ring-slate-200",
|
|
1230
|
+
style: {
|
|
1231
|
+
...position,
|
|
1232
|
+
width: `min(${layout.width}px, calc(100% - 1rem))`
|
|
1233
|
+
},
|
|
1234
|
+
children: [
|
|
1235
|
+
/* @__PURE__ */ jsx(
|
|
1236
|
+
"div",
|
|
1237
|
+
{
|
|
1238
|
+
"aria-hidden": true,
|
|
1239
|
+
className: "absolute inset-y-0 left-0 z-10 w-1.5 cursor-ew-resize hover:bg-fuchsia-500/20",
|
|
1240
|
+
onPointerDown: (event) => startDrag(event, "resize"),
|
|
1241
|
+
...dragHandlers
|
|
1242
|
+
}
|
|
1243
|
+
),
|
|
1244
|
+
/* @__PURE__ */ jsxs(
|
|
1245
|
+
"header",
|
|
1246
|
+
{
|
|
1247
|
+
className: "flex cursor-move touch-none items-center gap-1 border-b border-slate-100 px-2 py-1.5 select-none",
|
|
1248
|
+
onPointerDown: (event) => startDrag(event, "move"),
|
|
1249
|
+
...dragHandlers,
|
|
1250
|
+
children: [
|
|
1251
|
+
step ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1252
|
+
/* @__PURE__ */ jsx(
|
|
1253
|
+
ToolbarButton,
|
|
1254
|
+
{
|
|
1255
|
+
disabled: !step.onPrevious,
|
|
1256
|
+
label: step.previousLabel,
|
|
1257
|
+
onClick: () => step.onPrevious?.(),
|
|
1258
|
+
children: /* @__PURE__ */ jsx(Icon, { path: ICONS.back })
|
|
1259
|
+
}
|
|
1260
|
+
),
|
|
1261
|
+
/* @__PURE__ */ jsx(
|
|
1262
|
+
ToolbarButton,
|
|
1263
|
+
{
|
|
1264
|
+
disabled: !step.onNext,
|
|
1265
|
+
label: step.nextLabel,
|
|
1266
|
+
onClick: () => step.onNext?.(),
|
|
1267
|
+
children: /* @__PURE__ */ jsx(Icon, { path: ICONS.forward })
|
|
1268
|
+
}
|
|
1269
|
+
)
|
|
1270
|
+
] }) : null,
|
|
1271
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-0.5", children: [
|
|
1272
|
+
/* @__PURE__ */ jsx("h2", { className: "min-w-0 truncate px-1 text-sm font-semibold text-slate-800", children: title }),
|
|
1273
|
+
titleActions
|
|
1274
|
+
] }),
|
|
1275
|
+
onBack && onForward ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1276
|
+
/* @__PURE__ */ jsx(
|
|
1277
|
+
ToolbarButton,
|
|
1278
|
+
{
|
|
1279
|
+
disabled: !canGoBack,
|
|
1280
|
+
label: messages.viewer.backInHistory,
|
|
1281
|
+
onClick: onBack,
|
|
1282
|
+
children: /* @__PURE__ */ jsx(Icon, { path: ICONS.undo })
|
|
1283
|
+
}
|
|
1284
|
+
),
|
|
1285
|
+
/* @__PURE__ */ jsx(
|
|
1286
|
+
ToolbarButton,
|
|
1287
|
+
{
|
|
1288
|
+
disabled: !canGoForward,
|
|
1289
|
+
label: messages.viewer.forwardInHistory,
|
|
1290
|
+
onClick: onForward,
|
|
1291
|
+
children: /* @__PURE__ */ jsx(Icon, { path: ICONS.redo })
|
|
1292
|
+
}
|
|
1293
|
+
)
|
|
1294
|
+
] }) : null,
|
|
1295
|
+
/* @__PURE__ */ jsx(
|
|
1296
|
+
ToolbarButton,
|
|
1297
|
+
{
|
|
1298
|
+
label: messages.viewer.minimize,
|
|
1299
|
+
onClick: () => updateLayout({ ...layout, minimized: true }),
|
|
1300
|
+
children: /* @__PURE__ */ jsx(Icon, { path: ICONS.minimize })
|
|
1301
|
+
}
|
|
1302
|
+
),
|
|
1303
|
+
/* @__PURE__ */ jsx(ToolbarButton, { label: messages.viewer.close, onClick: onClose, children: /* @__PURE__ */ jsx(Icon, { path: ICONS.close }) })
|
|
1304
|
+
]
|
|
1305
|
+
}
|
|
1306
|
+
),
|
|
1307
|
+
toolbar ? /* @__PURE__ */ jsx("div", { className: "border-b border-slate-100 px-2 py-1.5", children: toolbar }) : suggestions.length > 0 ? /* @__PURE__ */ jsx(
|
|
1308
|
+
"nav",
|
|
1309
|
+
{
|
|
1310
|
+
"aria-label": messages.viewer.suggestedViews,
|
|
1311
|
+
className: "grid grid-cols-[repeat(auto-fit,minmax(5.25rem,1fr))] gap-1 border-b border-slate-100 px-2 py-1.5",
|
|
1312
|
+
title: messages.viewer.suggestedViewsHint,
|
|
1313
|
+
children: suggestions.map((suggestion) => /* @__PURE__ */ jsx(
|
|
1314
|
+
SuggestionChip,
|
|
1315
|
+
{
|
|
1316
|
+
active: suggestion.direction.key === activeDirectionKey,
|
|
1317
|
+
onSelect: (candidate) => onSelectSuggestion(suggestion, candidate),
|
|
1318
|
+
shownPhotoId,
|
|
1319
|
+
showPlace: severalViewpoints,
|
|
1320
|
+
suggestion
|
|
1321
|
+
},
|
|
1322
|
+
suggestion.direction.key
|
|
1323
|
+
))
|
|
1324
|
+
}
|
|
1325
|
+
) : null,
|
|
1326
|
+
/* @__PURE__ */ jsxs("div", { className: "min-h-0 overflow-y-auto", children: [
|
|
1327
|
+
status ? /* @__PURE__ */ jsx("p", { className: "px-3 py-2 text-xs text-slate-500", role: "status", children: status }) : null,
|
|
1328
|
+
children,
|
|
1329
|
+
footer ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-slate-600", children: footer }) : null,
|
|
1330
|
+
drawer ? /* @__PURE__ */ jsxs("div", { className: "border-t border-slate-100", children: [
|
|
1331
|
+
/* @__PURE__ */ jsxs(
|
|
1332
|
+
"button",
|
|
1333
|
+
{
|
|
1334
|
+
"aria-expanded": drawerOpen,
|
|
1335
|
+
className: "flex w-full items-center justify-between px-3 py-2 text-xs font-medium text-slate-700 hover:bg-slate-50",
|
|
1336
|
+
onClick: () => setDrawerOpen((open) => !open),
|
|
1337
|
+
type: "button",
|
|
1338
|
+
children: [
|
|
1339
|
+
drawer.label,
|
|
1340
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: drawerOpen ? "inline-flex rotate-90" : "inline-flex", children: /* @__PURE__ */ jsx(Icon, { className: "size-3.5", path: ICONS.forward }) })
|
|
1341
|
+
]
|
|
1342
|
+
}
|
|
1343
|
+
),
|
|
1344
|
+
drawerOpen ? /* @__PURE__ */ jsx("div", { className: "px-2 pb-2", children: drawer.content }) : null
|
|
1345
|
+
] }) : null
|
|
1346
|
+
] })
|
|
1347
|
+
]
|
|
1348
|
+
}
|
|
1349
|
+
);
|
|
1350
|
+
};
|
|
1351
|
+
var SOURCE_DIRECTIONS = "viewpoint-directions";
|
|
1352
|
+
var SOURCE_POINTS = "viewpoint-points";
|
|
1353
|
+
var SOURCE_LINE = "viewpoint-line";
|
|
1354
|
+
var VIEWPOINT_DIRECTION_LAYER_ID = "viewpoint-direction-fill";
|
|
1355
|
+
var VIEWPOINT_DEFAULT_COLOR = "#c026d3";
|
|
1356
|
+
var directionLengthMeters = (zoom) => Math.max(8, coneRadiusMeters(zoom) * 3);
|
|
1357
|
+
var ViewpointLayer = ({
|
|
1358
|
+
viewpoints,
|
|
1359
|
+
suggestions,
|
|
1360
|
+
activeDirectionKey,
|
|
1361
|
+
zoom,
|
|
1362
|
+
line,
|
|
1363
|
+
color = VIEWPOINT_DEFAULT_COLOR
|
|
1364
|
+
}) => {
|
|
1365
|
+
const length = directionLengthMeters(zoom);
|
|
1366
|
+
const directions = {
|
|
1367
|
+
type: "FeatureCollection",
|
|
1368
|
+
features: suggestions.map(({ viewpoint, direction, candidates }) => ({
|
|
1369
|
+
...viewConeGeoJson(viewpoint.lngLat, direction.bearing, 40, length),
|
|
1370
|
+
properties: {
|
|
1371
|
+
key: direction.key,
|
|
1372
|
+
active: direction.key === activeDirectionKey,
|
|
1373
|
+
hasPhoto: candidates.length > 0
|
|
1374
|
+
}
|
|
1375
|
+
}))
|
|
1376
|
+
};
|
|
1377
|
+
const points = {
|
|
1378
|
+
type: "FeatureCollection",
|
|
1379
|
+
features: viewpoints.map(
|
|
1380
|
+
(viewpoint) => ({
|
|
1381
|
+
type: "Feature",
|
|
1382
|
+
properties: { id: viewpoint.id },
|
|
1383
|
+
geometry: { type: "Point", coordinates: viewpoint.lngLat }
|
|
1384
|
+
})
|
|
1385
|
+
)
|
|
1386
|
+
};
|
|
1387
|
+
const lineFeature = {
|
|
1388
|
+
type: "FeatureCollection",
|
|
1389
|
+
features: line && line.length > 1 ? [{ type: "Feature", properties: {}, geometry: { type: "LineString", coordinates: line } }] : []
|
|
1390
|
+
};
|
|
1391
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1392
|
+
/* @__PURE__ */ jsx(Source, { id: SOURCE_LINE, type: "geojson", data: lineFeature }),
|
|
1393
|
+
/* @__PURE__ */ jsx(
|
|
1394
|
+
Layer,
|
|
1395
|
+
{
|
|
1396
|
+
id: "viewpoint-line",
|
|
1397
|
+
type: "line",
|
|
1398
|
+
source: SOURCE_LINE,
|
|
1399
|
+
layout: { "line-cap": "round", "line-join": "round" },
|
|
1400
|
+
paint: { "line-color": color, "line-width": 5, "line-opacity": 0.5 }
|
|
1401
|
+
}
|
|
1402
|
+
),
|
|
1403
|
+
/* @__PURE__ */ jsx(Source, { id: SOURCE_DIRECTIONS, type: "geojson", data: directions }),
|
|
1404
|
+
/* @__PURE__ */ jsx(
|
|
1405
|
+
Layer,
|
|
1406
|
+
{
|
|
1407
|
+
id: VIEWPOINT_DIRECTION_LAYER_ID,
|
|
1408
|
+
type: "fill",
|
|
1409
|
+
source: SOURCE_DIRECTIONS,
|
|
1410
|
+
paint: {
|
|
1411
|
+
"fill-color": color,
|
|
1412
|
+
"fill-opacity": ["case", ["get", "active"], 0.55, ["get", "hasPhoto"], 0.18, 0.04]
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
),
|
|
1416
|
+
/* @__PURE__ */ jsx(
|
|
1417
|
+
Layer,
|
|
1418
|
+
{
|
|
1419
|
+
id: "viewpoint-direction-line",
|
|
1420
|
+
type: "line",
|
|
1421
|
+
source: SOURCE_DIRECTIONS,
|
|
1422
|
+
paint: {
|
|
1423
|
+
"line-color": color,
|
|
1424
|
+
"line-width": ["case", ["get", "active"], 2, 1],
|
|
1425
|
+
"line-dasharray": [2, 1.5],
|
|
1426
|
+
"line-opacity": ["case", ["get", "hasPhoto"], 0.9, 0.35]
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
),
|
|
1430
|
+
/* @__PURE__ */ jsx(Source, { id: SOURCE_POINTS, type: "geojson", data: points }),
|
|
1431
|
+
/* @__PURE__ */ jsx(
|
|
1432
|
+
Layer,
|
|
1433
|
+
{
|
|
1434
|
+
id: "viewpoint-point",
|
|
1435
|
+
type: "circle",
|
|
1436
|
+
source: SOURCE_POINTS,
|
|
1437
|
+
paint: {
|
|
1438
|
+
"circle-radius": 5,
|
|
1439
|
+
"circle-color": "#ffffff",
|
|
1440
|
+
"circle-stroke-color": color,
|
|
1441
|
+
"circle-stroke-width": 2.5
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
)
|
|
1445
|
+
] });
|
|
1446
|
+
};
|
|
1447
|
+
var viewDirectionKeyFromFeatures = (features) => {
|
|
1448
|
+
const hit = features?.find((feature) => feature.layer?.id === VIEWPOINT_DIRECTION_LAYER_ID);
|
|
1449
|
+
const key = hit?.properties?.key;
|
|
1450
|
+
return typeof key === "string" ? key : null;
|
|
1451
|
+
};
|
|
1452
|
+
var samePhoto = (a, b) => a != null && a.providerId === b.providerId && a.photoId === b.photoId;
|
|
1453
|
+
var useViewpointSessionStore = create()((set, get) => ({
|
|
1454
|
+
sessionId: 0,
|
|
1455
|
+
viewpoints: [],
|
|
1456
|
+
line: null,
|
|
1457
|
+
activeDirectionKey: null,
|
|
1458
|
+
history: [],
|
|
1459
|
+
historyIndex: -1,
|
|
1460
|
+
actions: {
|
|
1461
|
+
open: ({ viewpoints, line = null }) => set((state) => ({
|
|
1462
|
+
sessionId: state.sessionId + 1,
|
|
1463
|
+
viewpoints,
|
|
1464
|
+
line,
|
|
1465
|
+
activeDirectionKey: null
|
|
1466
|
+
})),
|
|
1467
|
+
showPhoto: (entry) => set((state) => {
|
|
1468
|
+
const current = state.history[state.historyIndex];
|
|
1469
|
+
if (samePhoto(current?.photo, entry.photo)) {
|
|
1470
|
+
if (entry.directionKey == null || entry.directionKey === current?.directionKey) {
|
|
1471
|
+
return entry.directionKey != null && entry.directionKey !== state.activeDirectionKey ? { activeDirectionKey: entry.directionKey } : state;
|
|
1472
|
+
}
|
|
1473
|
+
const history2 = [...state.history];
|
|
1474
|
+
history2[state.historyIndex] = { ...entry };
|
|
1475
|
+
return { history: history2, activeDirectionKey: entry.directionKey };
|
|
1476
|
+
}
|
|
1477
|
+
const history = [...state.history.slice(0, state.historyIndex + 1), entry].slice(
|
|
1478
|
+
-100
|
|
1479
|
+
);
|
|
1480
|
+
return {
|
|
1481
|
+
history,
|
|
1482
|
+
historyIndex: history.length - 1,
|
|
1483
|
+
activeDirectionKey: entry.directionKey ?? state.activeDirectionKey
|
|
1484
|
+
};
|
|
1485
|
+
}),
|
|
1486
|
+
back: () => {
|
|
1487
|
+
const { history, historyIndex } = get();
|
|
1488
|
+
const entry = history[historyIndex - 1];
|
|
1489
|
+
if (!entry) {
|
|
1490
|
+
return null;
|
|
1491
|
+
}
|
|
1492
|
+
set({ historyIndex: historyIndex - 1, activeDirectionKey: entry.directionKey });
|
|
1493
|
+
return entry;
|
|
1494
|
+
},
|
|
1495
|
+
forward: () => {
|
|
1496
|
+
const { history, historyIndex } = get();
|
|
1497
|
+
const entry = history[historyIndex + 1];
|
|
1498
|
+
if (!entry) {
|
|
1499
|
+
return null;
|
|
1500
|
+
}
|
|
1501
|
+
set({ historyIndex: historyIndex + 1, activeDirectionKey: entry.directionKey });
|
|
1502
|
+
return entry;
|
|
1503
|
+
},
|
|
1504
|
+
close: () => set({ viewpoints: [], line: null, activeDirectionKey: null }),
|
|
1505
|
+
reset: () => set({
|
|
1506
|
+
viewpoints: [],
|
|
1507
|
+
line: null,
|
|
1508
|
+
activeDirectionKey: null,
|
|
1509
|
+
history: [],
|
|
1510
|
+
historyIndex: -1
|
|
1511
|
+
})
|
|
1512
|
+
}
|
|
1513
|
+
}));
|
|
1514
|
+
var useViewpoints = () => useViewpointSessionStore((state) => state.viewpoints);
|
|
1515
|
+
var useViewpointLine = () => useViewpointSessionStore((state) => state.line);
|
|
1516
|
+
var useActiveDirectionKey = () => useViewpointSessionStore((state) => state.activeDirectionKey);
|
|
1517
|
+
var useCurrentHistoryEntry = () => useViewpointSessionStore((state) => state.history[state.historyIndex] ?? null);
|
|
1518
|
+
var useCanGoBack = () => useViewpointSessionStore((state) => state.historyIndex > 0);
|
|
1519
|
+
var useCanGoForward = () => useViewpointSessionStore((state) => state.historyIndex < state.history.length - 1);
|
|
1520
|
+
var getViewpointSession = () => {
|
|
1521
|
+
const { actions, history, historyIndex } = useViewpointSessionStore.getState();
|
|
1522
|
+
return { actions, current: history[historyIndex] ?? null };
|
|
1523
|
+
};
|
|
1524
|
+
var DEFAULT_SOURCES = [mapillaryPhotoSource];
|
|
1525
|
+
var useViewSuggestions = (viewpoints, {
|
|
1526
|
+
maxAgeYears,
|
|
1527
|
+
photoTypes,
|
|
1528
|
+
limit,
|
|
1529
|
+
filterPhoto,
|
|
1530
|
+
sources = DEFAULT_SOURCES,
|
|
1531
|
+
enabled = true
|
|
1532
|
+
} = {}) => {
|
|
1533
|
+
const [now] = useState(() => Date.now());
|
|
1534
|
+
const requests = viewpoints.flatMap(
|
|
1535
|
+
(viewpoint) => sources.map((source) => ({ viewpoint, source }))
|
|
1536
|
+
);
|
|
1537
|
+
const queries = useQueries({
|
|
1538
|
+
queries: requests.map(({ viewpoint, source }) => ({
|
|
1539
|
+
queryKey: [
|
|
1540
|
+
"street-imagery",
|
|
1541
|
+
"photos-near",
|
|
1542
|
+
source.id,
|
|
1543
|
+
viewpoint.lngLat[0],
|
|
1544
|
+
viewpoint.lngLat[1]
|
|
1545
|
+
],
|
|
1546
|
+
queryFn: ({ signal }) => source.fetchNear(viewpoint.lngLat, signal),
|
|
1547
|
+
enabled,
|
|
1548
|
+
staleTime: 10 * 60 * 1e3
|
|
1549
|
+
}))
|
|
1550
|
+
});
|
|
1551
|
+
const photosByViewpointId = /* @__PURE__ */ new Map();
|
|
1552
|
+
requests.forEach(({ viewpoint }, index) => {
|
|
1553
|
+
const photos = queries[index]?.data ?? [];
|
|
1554
|
+
const kept = filterPhoto ? photos.filter(filterPhoto) : photos;
|
|
1555
|
+
photosByViewpointId.set(viewpoint.id, [
|
|
1556
|
+
...photosByViewpointId.get(viewpoint.id) ?? [],
|
|
1557
|
+
...kept
|
|
1558
|
+
]);
|
|
1559
|
+
});
|
|
1560
|
+
const suggestions = buildViewSuggestions(
|
|
1561
|
+
viewpoints,
|
|
1562
|
+
(viewpoint) => photosByViewpointId.get(viewpoint.id) ?? [],
|
|
1563
|
+
{
|
|
1564
|
+
now,
|
|
1565
|
+
maxAgeMs: maxAgeYears == null ? void 0 : yearsToMs(maxAgeYears),
|
|
1566
|
+
photoTypes,
|
|
1567
|
+
limit
|
|
1568
|
+
}
|
|
1569
|
+
);
|
|
1570
|
+
return {
|
|
1571
|
+
suggestions,
|
|
1572
|
+
isLoading: enabled && queries.some((query) => query.isPending),
|
|
1573
|
+
// An error only when every source failed; one failing provider still leaves suggestions.
|
|
1574
|
+
isError: queries.length > 0 && queries.every((query) => query.isError)
|
|
1575
|
+
};
|
|
1576
|
+
};
|
|
1577
|
+
var STALE_TIME = 10 * 60 * 1e3;
|
|
1578
|
+
var useMapillaryMapFeatureImages = (featureId, { shape = SIGN_TARGET } = {}) => useQuery({
|
|
1579
|
+
queryKey: ["street-imagery", "mapillary-map-feature", featureId, shape],
|
|
1580
|
+
queryFn: ({ signal }) => fetchMapFeatureImages(featureId, { shape, signal }),
|
|
1581
|
+
enabled: !!featureId,
|
|
1582
|
+
staleTime: STALE_TIME
|
|
1583
|
+
});
|
|
1584
|
+
var useMapillaryMapFeaturesNear = (lngLat, {
|
|
1585
|
+
radiusMeters = 40,
|
|
1586
|
+
objectValues,
|
|
1587
|
+
enabled = true
|
|
1588
|
+
} = {}) => useQuery({
|
|
1589
|
+
queryKey: ["street-imagery", "mapillary-map-features-near", lngLat, radiusMeters, objectValues],
|
|
1590
|
+
queryFn: async ({ signal }) => {
|
|
1591
|
+
const center = lngLat;
|
|
1592
|
+
const features = await fetchMapillaryMapFeaturesInBbox(bboxAround(center, radiusMeters), {
|
|
1593
|
+
objectValues,
|
|
1594
|
+
signal
|
|
1595
|
+
});
|
|
1596
|
+
return features.map((feature) => ({ ...feature, distanceMeters: distanceMeters(center, feature.lngLat) })).filter((feature) => feature.distanceMeters <= radiusMeters).sort((a, b) => a.distanceMeters - b.distanceMeters);
|
|
1597
|
+
},
|
|
1598
|
+
enabled: enabled && !!lngLat,
|
|
1599
|
+
staleTime: STALE_TIME
|
|
1600
|
+
});
|
|
1601
|
+
var useMapillaryImageDetections = (imageId, { filter, filterKey } = {}) => useQuery({
|
|
1602
|
+
queryKey: ["street-imagery", "mapillary-detections", imageId, filterKey ?? null],
|
|
1603
|
+
queryFn: ({ signal }) => fetchImageDetections(imageId, { filter, signal }),
|
|
1604
|
+
enabled: !!imageId,
|
|
1605
|
+
staleTime: STALE_TIME
|
|
1606
|
+
});
|
|
1607
|
+
var useSelectedMapillaryFeature = ({
|
|
1608
|
+
featureId,
|
|
1609
|
+
shownPhotoId,
|
|
1610
|
+
minCapturedAt,
|
|
1611
|
+
shape
|
|
1612
|
+
}) => {
|
|
1613
|
+
const { data, isLoading, isError } = useMapillaryMapFeatureImages(featureId, { shape });
|
|
1614
|
+
const shownImage = data?.images.find((image) => image.id === shownPhotoId) ?? null;
|
|
1615
|
+
const firstImage = data ? bestTargetImage(data.images, data.feature.lngLat, {
|
|
1616
|
+
minCapturedAt: minCapturedAt ?? void 0,
|
|
1617
|
+
shape
|
|
1618
|
+
}) ?? null : null;
|
|
1619
|
+
return { data: data ?? null, isLoading, isError, shownImage, firstImage };
|
|
1620
|
+
};
|
|
1621
|
+
var useLocationPickStore = create()((set) => ({
|
|
1622
|
+
armedOpenerId: null,
|
|
1623
|
+
actions: {
|
|
1624
|
+
arm: (openerId) => set({ armedOpenerId: openerId }),
|
|
1625
|
+
disarm: () => set((state) => state.armedOpenerId == null ? state : { armedOpenerId: null }),
|
|
1626
|
+
toggle: (openerId) => set((state) => ({ armedOpenerId: state.armedOpenerId === openerId ? null : openerId }))
|
|
1627
|
+
}
|
|
1628
|
+
}));
|
|
1629
|
+
var useArmedLocationOpenerId = () => useLocationPickStore((state) => state.armedOpenerId);
|
|
1630
|
+
var useLocationPickActions = () => useLocationPickStore((state) => state.actions);
|
|
1631
|
+
|
|
1632
|
+
// src/openers/LocationPickOnMap.tsx
|
|
1633
|
+
var roundCoordinate = (value) => Number(value.toFixed(7));
|
|
1634
|
+
var LocationPickOnMap = ({ onPick }) => {
|
|
1635
|
+
const { current: map } = useMap();
|
|
1636
|
+
const armedOpenerId = useArmedLocationOpenerId();
|
|
1637
|
+
const { disarm } = useLocationPickActions();
|
|
1638
|
+
useEffect(
|
|
1639
|
+
function openArmedOpenerOnNextMapClick() {
|
|
1640
|
+
if (!map || !armedOpenerId) {
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
const opener = findLocationOpener(armedOpenerId);
|
|
1644
|
+
if (!opener) {
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
const onClick = (event) => {
|
|
1648
|
+
const target = {
|
|
1649
|
+
lngLat: [roundCoordinate(event.lngLat.lng), roundCoordinate(event.lngLat.lat)],
|
|
1650
|
+
zoom: map.getZoom()
|
|
1651
|
+
};
|
|
1652
|
+
openLocationInNewTab(opener, target);
|
|
1653
|
+
disarm();
|
|
1654
|
+
onPick?.(target, opener);
|
|
1655
|
+
};
|
|
1656
|
+
const onKeyDown = (event) => {
|
|
1657
|
+
if (event.key === "Escape") {
|
|
1658
|
+
disarm();
|
|
1659
|
+
}
|
|
1660
|
+
};
|
|
1661
|
+
map.on("click", onClick);
|
|
1662
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1663
|
+
return function stopListeningForPick() {
|
|
1664
|
+
map.off("click", onClick);
|
|
1665
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
1666
|
+
};
|
|
1667
|
+
},
|
|
1668
|
+
[armedOpenerId, disarm, map, onPick]
|
|
1669
|
+
);
|
|
1670
|
+
return null;
|
|
1671
|
+
};
|
|
1672
|
+
var SelectedMapFeatureLayer = ({
|
|
1673
|
+
data,
|
|
1674
|
+
shownImage,
|
|
1675
|
+
providers,
|
|
1676
|
+
bbox,
|
|
1677
|
+
zoom,
|
|
1678
|
+
color = MAP_FEATURE_COLOR
|
|
1679
|
+
}) => {
|
|
1680
|
+
const drawnFeatures = useAllProviderMapFeatures(providers, bbox, zoom);
|
|
1681
|
+
const target = data ? drawnFeatures.find((feature) => feature.featureId === data.feature.id)?.lngLat ?? data.feature.lngLat : null;
|
|
1682
|
+
const camera = shownImage?.lngLat;
|
|
1683
|
+
const points = {
|
|
1684
|
+
type: "FeatureCollection",
|
|
1685
|
+
features: target ? [{ type: "Feature", properties: {}, geometry: { type: "Point", coordinates: target } }] : []
|
|
1686
|
+
};
|
|
1687
|
+
const line = {
|
|
1688
|
+
type: "FeatureCollection",
|
|
1689
|
+
features: target && camera ? [
|
|
1690
|
+
{
|
|
1691
|
+
type: "Feature",
|
|
1692
|
+
properties: {},
|
|
1693
|
+
geometry: { type: "LineString", coordinates: [camera, target] }
|
|
1694
|
+
}
|
|
1695
|
+
] : []
|
|
1696
|
+
};
|
|
1697
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1698
|
+
/* @__PURE__ */ jsx(Source, { data: line, id: "selected-map-feature-line", type: "geojson" }),
|
|
1699
|
+
/* @__PURE__ */ jsx(
|
|
1700
|
+
Layer,
|
|
1701
|
+
{
|
|
1702
|
+
id: "selected-map-feature-line",
|
|
1703
|
+
paint: { "line-color": SELECTION_COLOR, "line-width": 1.5, "line-dasharray": [2, 1.5] },
|
|
1704
|
+
source: "selected-map-feature-line",
|
|
1705
|
+
type: "line"
|
|
1706
|
+
}
|
|
1707
|
+
),
|
|
1708
|
+
/* @__PURE__ */ jsx(Source, { data: points, id: "selected-map-feature-point", type: "geojson" }),
|
|
1709
|
+
/* @__PURE__ */ jsx(
|
|
1710
|
+
Layer,
|
|
1711
|
+
{
|
|
1712
|
+
id: "selected-map-feature-disk",
|
|
1713
|
+
paint: {
|
|
1714
|
+
"circle-radius": 17,
|
|
1715
|
+
"circle-color": color,
|
|
1716
|
+
"circle-opacity": VIEW_SHAPE_FILL_OPACITY
|
|
1717
|
+
},
|
|
1718
|
+
source: "selected-map-feature-point",
|
|
1719
|
+
type: "circle"
|
|
1720
|
+
}
|
|
1721
|
+
),
|
|
1722
|
+
/* @__PURE__ */ jsx(
|
|
1723
|
+
Layer,
|
|
1724
|
+
{
|
|
1725
|
+
id: "selected-map-feature-dot",
|
|
1726
|
+
paint: {
|
|
1727
|
+
"circle-radius": ["interpolate", ["linear"], ["zoom"], 10, 1.8, 14, 3.6, 18, 4.8],
|
|
1728
|
+
"circle-color": color
|
|
1729
|
+
},
|
|
1730
|
+
source: "selected-map-feature-point",
|
|
1731
|
+
type: "circle"
|
|
1732
|
+
}
|
|
1733
|
+
)
|
|
1734
|
+
] });
|
|
1735
|
+
};
|
|
1736
|
+
var MAPILLARY_FEATURE_BAR_LABELS = {
|
|
1737
|
+
en: {
|
|
1738
|
+
name: (value) => mapillaryValueName(value, "en"),
|
|
1739
|
+
seen: "Seen",
|
|
1740
|
+
noPhotos: "Mapillary lists no photos for this feature.",
|
|
1741
|
+
daysSummary: (photos, days) => `${photos} photos on ${days} days`,
|
|
1742
|
+
dayPhotos: (photos, canStep) => `${photos} photo${photos === 1 ? "" : "s"}${canStep ? " \u2014 click for the next one" : ""}`
|
|
1743
|
+
},
|
|
1744
|
+
de: {
|
|
1745
|
+
name: (value) => mapillaryValueName(value, "de"),
|
|
1746
|
+
seen: "Gesehen",
|
|
1747
|
+
noPhotos: "Mapillary f\xFChrt keine Fotos zu diesem Objekt.",
|
|
1748
|
+
daysSummary: (photos, days) => `${photos} Fotos an ${days} Tagen`,
|
|
1749
|
+
dayPhotos: (photos, canStep) => `${photos} Foto${photos === 1 ? "" : "s"}${canStep ? " \u2014 klicken f\xFCr das n\xE4chste" : ""}`
|
|
1750
|
+
}
|
|
1751
|
+
};
|
|
1752
|
+
var MapillaryFeatureBar = ({
|
|
1753
|
+
data,
|
|
1754
|
+
shownImage,
|
|
1755
|
+
onShow,
|
|
1756
|
+
labels: labelOverrides
|
|
1757
|
+
}) => {
|
|
1758
|
+
const { locale } = useStreetImageryI18n();
|
|
1759
|
+
const labels = { ...MAPILLARY_FEATURE_BAR_LABELS[locale], ...labelOverrides };
|
|
1760
|
+
const { feature, days, images } = data;
|
|
1761
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
1762
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", title: feature.value, children: [
|
|
1763
|
+
/* @__PURE__ */ jsx(
|
|
1764
|
+
"img",
|
|
1765
|
+
{
|
|
1766
|
+
alt: "",
|
|
1767
|
+
className: "size-7 shrink-0",
|
|
1768
|
+
onError: (event) => {
|
|
1769
|
+
event.currentTarget.style.display = "none";
|
|
1770
|
+
},
|
|
1771
|
+
src: mapillaryIconUrl(feature.value)
|
|
1772
|
+
},
|
|
1773
|
+
feature.value
|
|
1774
|
+
),
|
|
1775
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
1776
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-sm leading-tight font-medium text-slate-900", children: labels.name(feature.value) }),
|
|
1777
|
+
/* @__PURE__ */ jsxs("p", { className: "truncate text-xs leading-tight text-slate-500", children: [
|
|
1778
|
+
labels.seen,
|
|
1779
|
+
" ",
|
|
1780
|
+
/* @__PURE__ */ jsx(PhotoDate, { timestamp: feature.firstSeenAt }),
|
|
1781
|
+
" \u2013",
|
|
1782
|
+
" ",
|
|
1783
|
+
/* @__PURE__ */ jsx(PhotoDate, { timestamp: feature.lastSeenAt })
|
|
1784
|
+
] })
|
|
1785
|
+
] })
|
|
1786
|
+
] }),
|
|
1787
|
+
days.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-500", children: labels.noPhotos }) : /* @__PURE__ */ jsx(
|
|
1788
|
+
"div",
|
|
1789
|
+
{
|
|
1790
|
+
"aria-label": labels.daysSummary(images.length, days.length),
|
|
1791
|
+
className: "flex gap-1 overflow-x-auto",
|
|
1792
|
+
role: "group",
|
|
1793
|
+
children: days.map((day) => {
|
|
1794
|
+
const noon = /* @__PURE__ */ new Date(`${day.day}T12:00:00Z`);
|
|
1795
|
+
const shownIndex = shownImage ? day.images.findIndex((image) => image.id === shownImage.id) : -1;
|
|
1796
|
+
const active = shownIndex >= 0;
|
|
1797
|
+
return /* @__PURE__ */ jsxs(
|
|
1798
|
+
"button",
|
|
1799
|
+
{
|
|
1800
|
+
"aria-pressed": active,
|
|
1801
|
+
className: `shrink-0 rounded-md border px-2 py-1 text-xs whitespace-nowrap ${active ? "border-amber-500 bg-amber-100 text-amber-950" : "border-slate-300 bg-white text-slate-700 hover:border-slate-400"}`,
|
|
1802
|
+
onClick: () => {
|
|
1803
|
+
const next = active ? day.images[(shownIndex + 1) % day.images.length] : day.best;
|
|
1804
|
+
if (next) {
|
|
1805
|
+
onShow(next);
|
|
1806
|
+
}
|
|
1807
|
+
},
|
|
1808
|
+
title: `${formatDateTooltip(noon, locale)}
|
|
1809
|
+
${labels.dayPhotos(day.images.length, active && day.images.length > 1)}`,
|
|
1810
|
+
type: "button",
|
|
1811
|
+
children: [
|
|
1812
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: formatMonth(noon, locale) }),
|
|
1813
|
+
" ",
|
|
1814
|
+
/* @__PURE__ */ jsx(
|
|
1815
|
+
PhotoCount,
|
|
1816
|
+
{
|
|
1817
|
+
className: `align-[-1px] ${active ? "text-amber-800" : "text-slate-500"}`,
|
|
1818
|
+
index: active ? shownIndex + 1 : void 0,
|
|
1819
|
+
total: day.images.length
|
|
1820
|
+
}
|
|
1821
|
+
)
|
|
1822
|
+
]
|
|
1823
|
+
},
|
|
1824
|
+
day.day
|
|
1825
|
+
);
|
|
1826
|
+
})
|
|
1827
|
+
}
|
|
1828
|
+
)
|
|
1829
|
+
] });
|
|
1830
|
+
};
|
|
1831
|
+
var DEFAULT_YEAR_LINES = [1, 2, 3, 4];
|
|
1832
|
+
var BINS = 60;
|
|
1833
|
+
var STEP = 1e-3;
|
|
1834
|
+
var CHART_HEIGHT_PX = 36;
|
|
1835
|
+
var RED = "#dc2626";
|
|
1836
|
+
var HANDLE_CLASS = "pointer-events-none absolute inset-0 m-0 h-full w-full cursor-pointer appearance-none bg-transparent focus:outline-none [&::-webkit-slider-runnable-track]:appearance-none [&::-webkit-slider-runnable-track]:bg-transparent [&::-moz-range-track]:bg-transparent [&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:cursor-grab [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-white [&::-webkit-slider-thumb]:bg-slate-800 [&::-webkit-slider-thumb]:shadow [&::-moz-range-thumb]:pointer-events-auto [&::-moz-range-thumb]:box-border [&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:cursor-grab [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-white [&::-moz-range-thumb]:bg-slate-800 [&::-moz-range-thumb]:shadow focus-visible:[&::-webkit-slider-thumb]:ring-2 focus-visible:[&::-webkit-slider-thumb]:ring-sky-500 focus-visible:[&::-moz-range-thumb]:ring-2 focus-visible:[&::-moz-range-thumb]:ring-sky-500";
|
|
1837
|
+
var percent = (position) => `${position * 100}%`;
|
|
1838
|
+
var PhotoDateRangeFilter = ({
|
|
1839
|
+
value,
|
|
1840
|
+
onChange,
|
|
1841
|
+
capturedAt,
|
|
1842
|
+
yearLines = DEFAULT_YEAR_LINES,
|
|
1843
|
+
recommendedMaxAgeYears,
|
|
1844
|
+
markers = [],
|
|
1845
|
+
maxYears,
|
|
1846
|
+
now: nowProp,
|
|
1847
|
+
dateInputs = "collapsed",
|
|
1848
|
+
className,
|
|
1849
|
+
allDatesAction = true
|
|
1850
|
+
}) => {
|
|
1851
|
+
const { locale, messages } = useStreetImageryI18n();
|
|
1852
|
+
const text = messages.dateFilter;
|
|
1853
|
+
const [startNow] = useState(() => Date.now());
|
|
1854
|
+
const now = nowProp ?? startNow;
|
|
1855
|
+
const scale = { now, maxYears };
|
|
1856
|
+
const [dragged, setDragged] = useState(null);
|
|
1857
|
+
const fromInput = useRef(null);
|
|
1858
|
+
const toInput = useRef(null);
|
|
1859
|
+
const positions = dragged ?? dateRangeToSliderPositions(value, scale);
|
|
1860
|
+
const shownRange = dragged ? sliderPositionsToDateRange(dragged, scale) : value;
|
|
1861
|
+
const readPositions = (moved) => {
|
|
1862
|
+
const from = Number(fromInput.current?.value ?? positions.from);
|
|
1863
|
+
const to = Number(toInput.current?.value ?? positions.to);
|
|
1864
|
+
return moved === "from" ? { from: Math.min(from, to), to } : { from, to: Math.max(from, to) };
|
|
1865
|
+
};
|
|
1866
|
+
const commitOnRelease = (moved) => (input) => {
|
|
1867
|
+
if (!input) {
|
|
1868
|
+
return void 0;
|
|
1869
|
+
}
|
|
1870
|
+
const commit = () => {
|
|
1871
|
+
setDragged(null);
|
|
1872
|
+
const next = sliderPositionsToDateRange(readPositions(moved), scale);
|
|
1873
|
+
const other = moved === "from" ? "to" : "from";
|
|
1874
|
+
onChange({ ...next, [other]: value[other] });
|
|
1875
|
+
};
|
|
1876
|
+
input.addEventListener("change", commit);
|
|
1877
|
+
return () => {
|
|
1878
|
+
input.removeEventListener("change", commit);
|
|
1879
|
+
};
|
|
1880
|
+
};
|
|
1881
|
+
const trackDrag = (moved, event) => {
|
|
1882
|
+
if (event.type === "input") {
|
|
1883
|
+
setDragged(readPositions(moved));
|
|
1884
|
+
}
|
|
1885
|
+
};
|
|
1886
|
+
const bins = capturedAt ? dateSliderBins(capturedAt, scale, BINS) : [];
|
|
1887
|
+
const maxCount = Math.max(1, ...bins);
|
|
1888
|
+
const years = [
|
|
1889
|
+
...new Set(recommendedMaxAgeYears ? [...yearLines, recommendedMaxAgeYears] : yearLines)
|
|
1890
|
+
].map((count) => ({ count, position: dateSliderPosition(yearsAgoMs(count, now), scale) })).filter(({ position }) => position > 0 && position < 1);
|
|
1891
|
+
const shownMarkers = markers.map((marker) => {
|
|
1892
|
+
const time = typeof marker.date === "number" ? marker.date : parseIsoDateStartMs(marker.date);
|
|
1893
|
+
return { ...marker, position: dateSliderPosition(time, scale) };
|
|
1894
|
+
}).filter(({ position }) => position > 0 && position < 1);
|
|
1895
|
+
const day = (isoDate) => formatDate(parseIsoDateStartMs(isoDate), locale);
|
|
1896
|
+
const rangeLabel = shownRange.from && shownRange.to ? text.between(day(shownRange.from), day(shownRange.to)) : shownRange.from ? text.since(day(shownRange.from)) : shownRange.to ? text.until(day(shownRange.to)) : text.allDates;
|
|
1897
|
+
const setYears = (count) => {
|
|
1898
|
+
onChange({ from: new Date(yearsAgoMs(count, now)).toISOString().slice(0, 10) });
|
|
1899
|
+
};
|
|
1900
|
+
const setDay = (key, input) => {
|
|
1901
|
+
if (input === "") {
|
|
1902
|
+
onChange({ ...value, [key]: void 0 });
|
|
1903
|
+
} else if (isIsoDate(input)) {
|
|
1904
|
+
onChange({ ...value, [key]: input });
|
|
1905
|
+
}
|
|
1906
|
+
};
|
|
1907
|
+
const isAllDates = !shownRange.from && !shownRange.to;
|
|
1908
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
1909
|
+
/* @__PURE__ */ jsx("div", { className: "mx-2", children: /* @__PURE__ */ jsxs(
|
|
1910
|
+
"div",
|
|
1911
|
+
{
|
|
1912
|
+
className: "relative",
|
|
1913
|
+
style: { height: CHART_HEIGHT_PX, marginTop: shownMarkers.length > 0 ? 14 : 0 },
|
|
1914
|
+
children: [
|
|
1915
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "absolute inset-0 flex items-end", children: bins.map((count, index) => {
|
|
1916
|
+
const start = index / BINS;
|
|
1917
|
+
const inRange = start + 1 / BINS > positions.from && start < positions.to;
|
|
1918
|
+
return /* @__PURE__ */ jsx(
|
|
1919
|
+
"div",
|
|
1920
|
+
{
|
|
1921
|
+
className: `flex-1 rounded-t-[1px] ${inRange ? "bg-slate-500" : "bg-slate-300"}`,
|
|
1922
|
+
style: {
|
|
1923
|
+
height: count === 0 ? 0 : Math.max(2, Math.log1p(count) / Math.log1p(maxCount) * CHART_HEIGHT_PX)
|
|
1924
|
+
},
|
|
1925
|
+
title: count > 0 ? text.photoCount(count) : void 0
|
|
1926
|
+
},
|
|
1927
|
+
index
|
|
1928
|
+
);
|
|
1929
|
+
}) }),
|
|
1930
|
+
years.map(({ count, position }) => /* @__PURE__ */ jsx(
|
|
1931
|
+
"div",
|
|
1932
|
+
{
|
|
1933
|
+
"aria-hidden": true,
|
|
1934
|
+
className: "pointer-events-none absolute inset-y-0 w-px -translate-x-1/2",
|
|
1935
|
+
style: {
|
|
1936
|
+
left: percent(position),
|
|
1937
|
+
backgroundColor: count === recommendedMaxAgeYears ? RED : "rgb(148 163 184 / 0.7)"
|
|
1938
|
+
}
|
|
1939
|
+
},
|
|
1940
|
+
count
|
|
1941
|
+
)),
|
|
1942
|
+
shownMarkers.map((marker) => /* @__PURE__ */ jsx(
|
|
1943
|
+
"div",
|
|
1944
|
+
{
|
|
1945
|
+
className: "pointer-events-none absolute inset-y-0 w-0 border-l-2 border-dashed",
|
|
1946
|
+
style: { left: percent(marker.position), borderColor: marker.color ?? RED },
|
|
1947
|
+
children: /* @__PURE__ */ jsx(
|
|
1948
|
+
"span",
|
|
1949
|
+
{
|
|
1950
|
+
className: "absolute -top-3.5 -translate-x-1/2 text-[10px] leading-none whitespace-nowrap",
|
|
1951
|
+
style: { color: marker.color ?? RED },
|
|
1952
|
+
children: marker.label
|
|
1953
|
+
}
|
|
1954
|
+
)
|
|
1955
|
+
},
|
|
1956
|
+
`${marker.date}-${marker.label}`
|
|
1957
|
+
))
|
|
1958
|
+
]
|
|
1959
|
+
}
|
|
1960
|
+
) }),
|
|
1961
|
+
/* @__PURE__ */ jsxs("div", { className: "relative h-4", children: [
|
|
1962
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-x-2 top-1/2 h-1 -translate-y-1/2 rounded-full bg-slate-200", children: /* @__PURE__ */ jsx(
|
|
1963
|
+
"div",
|
|
1964
|
+
{
|
|
1965
|
+
className: "absolute inset-y-0 rounded-full bg-slate-700",
|
|
1966
|
+
style: {
|
|
1967
|
+
left: percent(positions.from),
|
|
1968
|
+
right: percent(1 - positions.to)
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
) }),
|
|
1972
|
+
/* @__PURE__ */ jsx(
|
|
1973
|
+
"input",
|
|
1974
|
+
{
|
|
1975
|
+
"aria-label": text.fromHandle,
|
|
1976
|
+
"aria-valuetext": shownRange.from ? day(shownRange.from) : text.allDates,
|
|
1977
|
+
className: HANDLE_CLASS,
|
|
1978
|
+
max: 1,
|
|
1979
|
+
min: 0,
|
|
1980
|
+
onChange: (event) => {
|
|
1981
|
+
trackDrag("from", event.nativeEvent);
|
|
1982
|
+
},
|
|
1983
|
+
ref: (input) => {
|
|
1984
|
+
fromInput.current = input;
|
|
1985
|
+
return commitOnRelease("from")(input);
|
|
1986
|
+
},
|
|
1987
|
+
step: STEP,
|
|
1988
|
+
type: "range",
|
|
1989
|
+
value: positions.from
|
|
1990
|
+
}
|
|
1991
|
+
),
|
|
1992
|
+
/* @__PURE__ */ jsx(
|
|
1993
|
+
"input",
|
|
1994
|
+
{
|
|
1995
|
+
"aria-label": text.toHandle,
|
|
1996
|
+
"aria-valuetext": shownRange.to ? day(shownRange.to) : text.allDates,
|
|
1997
|
+
className: HANDLE_CLASS,
|
|
1998
|
+
max: 1,
|
|
1999
|
+
min: 0,
|
|
2000
|
+
onChange: (event) => {
|
|
2001
|
+
trackDrag("to", event.nativeEvent);
|
|
2002
|
+
},
|
|
2003
|
+
ref: (input) => {
|
|
2004
|
+
toInput.current = input;
|
|
2005
|
+
return commitOnRelease("to")(input);
|
|
2006
|
+
},
|
|
2007
|
+
step: STEP,
|
|
2008
|
+
type: "range",
|
|
2009
|
+
value: positions.to
|
|
2010
|
+
}
|
|
2011
|
+
)
|
|
2012
|
+
] }),
|
|
2013
|
+
/* @__PURE__ */ jsx("div", { className: "relative mx-2 h-4", children: years.map(({ count, position }) => /* @__PURE__ */ jsx(
|
|
2014
|
+
"button",
|
|
2015
|
+
{
|
|
2016
|
+
className: `absolute top-0 -translate-x-1/2 rounded px-0.5 text-[10px] leading-4 whitespace-nowrap hover:underline ${count === recommendedMaxAgeYears ? "font-semibold text-red-600" : "text-slate-500 hover:text-slate-900"}`,
|
|
2017
|
+
onClick: () => {
|
|
2018
|
+
setYears(count);
|
|
2019
|
+
},
|
|
2020
|
+
style: { left: percent(position) },
|
|
2021
|
+
title: count === recommendedMaxAgeYears ? text.recommendedMaxAge(count) : text.lastYears(count),
|
|
2022
|
+
type: "button",
|
|
2023
|
+
children: text.yearsShort(count)
|
|
2024
|
+
},
|
|
2025
|
+
count
|
|
2026
|
+
)) }),
|
|
2027
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-baseline justify-between gap-2 text-xs", children: [
|
|
2028
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-slate-700", children: rangeLabel }),
|
|
2029
|
+
isAllDates || !allDatesAction ? null : /* @__PURE__ */ jsx(
|
|
2030
|
+
"button",
|
|
2031
|
+
{
|
|
2032
|
+
className: "shrink-0 font-medium text-slate-600 underline decoration-slate-300 underline-offset-2 hover:text-slate-900",
|
|
2033
|
+
onClick: () => {
|
|
2034
|
+
onChange({});
|
|
2035
|
+
},
|
|
2036
|
+
type: "button",
|
|
2037
|
+
children: text.allDates
|
|
2038
|
+
}
|
|
2039
|
+
)
|
|
2040
|
+
] }),
|
|
2041
|
+
dateInputs === "none" ? null : /* @__PURE__ */ jsxs("details", { className: "mt-1 text-xs text-slate-600", open: dateInputs === "open" || void 0, children: [
|
|
2042
|
+
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer select-none hover:text-slate-900", children: text.exactDates }),
|
|
2043
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1.5 grid grid-cols-2 gap-2", children: ["from", "to"].map((key) => /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
|
|
2044
|
+
text[key],
|
|
2045
|
+
/* @__PURE__ */ jsx(
|
|
2046
|
+
"input",
|
|
2047
|
+
{
|
|
2048
|
+
className: "rounded-md border border-slate-200 px-2 py-1.5 text-sm text-slate-800",
|
|
2049
|
+
onChange: (event) => {
|
|
2050
|
+
setDay(key, event.target.value);
|
|
2051
|
+
},
|
|
2052
|
+
type: "date",
|
|
2053
|
+
value: value[key] ?? ""
|
|
2054
|
+
}
|
|
2055
|
+
)
|
|
2056
|
+
] }, key)) })
|
|
2057
|
+
] })
|
|
2058
|
+
] });
|
|
2059
|
+
};
|
|
658
2060
|
|
|
659
|
-
export { StreetLevelImagerySelectionOverlay, StreetLevelImagerySourcesAndLayers, StreetLevelImageryViewCone, StreetLevelImageryViewer, queryStreetImageryFeatures, resolveSelectedSequence, streetImageryInteractiveLayerIds,
|
|
2061
|
+
export { BASE_COLOR, FloatingPhotoViewer, FloatingViewerInfoButton, LocationPickOnMap, MAPILLARY_FEATURE_BAR_LABELS, MapillaryFeatureBar, PhotoCount, PhotoDate, PhotoDateRangeFilter, SELECTION_COLOR, SelectedMapFeatureLayer, StreetLevelImagerySelectionOverlay, StreetLevelImagerySourcesAndLayers, StreetLevelImageryViewCone, StreetLevelImageryViewer, VIEWPOINT_DEFAULT_COLOR, VIEWPOINT_DIRECTION_LAYER_ID, VIEW_SHAPE_FILL_OPACITY, ViewpointLayer, getViewpointSession, previousDataWhile, queryStreetImageryFeatures, resolveSelectedSequence, streetImageryInteractiveLayerIds, useActiveDirectionKey, useAllProviderMapFeatures, useAllProviderPhotos, useArmedLocationOpenerId, useCanGoBack, useCanGoForward, useCurrentHistoryEntry, useLocationPickActions, useMapViewportBbox, useMapillaryImageDetections, useMapillaryMapFeatureImages, useMapillaryMapFeaturesNear, usePhotoFullUrl, usePhotoThumbnail, useProviderMapFeatures, useProviderPhotos, useProviderSequences, useSelectedMapillaryFeature, useViewSuggestions, useViewpointLine, useViewpoints, viewDirectionKeyFromFeatures, viewSuggestionLabel };
|