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