Skip to content

Commit 801620f

Browse files
authored
feat(web): support set photo overlay on layer inspector [VIZ-1349] (#1522)
1 parent 837aa05 commit 801620f

File tree

22 files changed

+503
-69
lines changed

22 files changed

+503
-69
lines changed

server/pkg/builtin/manifest.yml

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,12 +2837,9 @@ extensions:
28372837
- id: enabled
28382838
type: bool
28392839
title: Enabled PhotoOverlay
2840-
# defaultValue: false
2841-
# description: xxxxxx
2840+
defaultValue: true
28422841
- id: cameraDuration
28432842
type: number
2844-
title: PhotoOverlay Camera Duration
2845-
# suffix: s
2846-
# min: 0
2847-
# defaultValue: 2
2848-
# description: xxxxxx
2843+
title: Camera Duration
2844+
defaultValue: 1
2845+
description: The duration (in seconds) it takes for the camera to fly to the captured position.

server/pkg/builtin/manifest_ja.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,3 +1462,4 @@ extensions:
14621462
title: 有効
14631463
cameraDuration:
14641464
title: カメラ移動時間
1465+
description: カメラがキャプチャされた位置へ移動するのにかかる時間(秒)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { filterVisibleItems } from "@reearth/beta/ui/fields/utils";
2+
import { usePhotoOverlayFetcher } from "@reearth/services/api";
3+
import { Item, convert } from "@reearth/services/api/propertyApi/utils";
4+
import { useCallback, useMemo } from "react";
5+
6+
export default ({ layerId, property }: { layerId: string; property?: any }) => {
7+
const { useCreateNLSPhotoOverlay } = usePhotoOverlayFetcher();
8+
9+
const visibleItems: Item[] | undefined = useMemo(
10+
() => filterVisibleItems(convert(property)),
11+
[property]
12+
);
13+
14+
const handlePhotoOverlayCreate = useCallback(async () => {
15+
if (!property) {
16+
await useCreateNLSPhotoOverlay({ layerId });
17+
}
18+
}, [layerId, property, useCreateNLSPhotoOverlay]);
19+
20+
return {
21+
visibleItems,
22+
handlePhotoOverlayCreate
23+
};
24+
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { SwitchField } from "@reearth/beta/ui/fields";
2+
import PropertyItem from "@reearth/beta/ui/fields/Properties";
3+
import { NLSPhotoOverlay } from "@reearth/services/api/layersApi/utils";
4+
import { useT } from "@reearth/services/i18n";
5+
import { styled } from "@reearth/services/theme";
6+
import { FC } from "react";
7+
8+
import useHooks from "./hooks";
9+
10+
type Props = {
11+
selectedLayerId: string;
12+
photoOverlay?: NLSPhotoOverlay;
13+
};
14+
15+
const PhotoOverlaySettings: FC<Props> = ({ selectedLayerId, photoOverlay }) => {
16+
const t = useT();
17+
18+
const { visibleItems, handlePhotoOverlayCreate } = useHooks({
19+
layerId: selectedLayerId,
20+
property: photoOverlay?.property
21+
});
22+
23+
return (
24+
<Wrapper>
25+
{visibleItems ? (
26+
visibleItems.map((i) => (
27+
<PropertyItem
28+
key={i.id ?? ""}
29+
propertyId={photoOverlay?.property?.id}
30+
item={i}
31+
/>
32+
))
33+
) : (
34+
<SwitchField
35+
title={t("Enable PhotoOverlay")}
36+
description={t("Show photo overlay when the user clicks on a layer")}
37+
value={false}
38+
onChange={handlePhotoOverlayCreate}
39+
/>
40+
)}
41+
</Wrapper>
42+
);
43+
};
44+
45+
const Wrapper = styled("div")(({ theme }) => ({
46+
display: "flex",
47+
flexDirection: "column",
48+
gap: theme.spacing.large
49+
}));
50+
51+
export default PhotoOverlaySettings;

web/src/beta/features/Editor/Map/InspectorPanel/LayerInspector/index.tsx

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import {
44
SelectedFeature,
55
SelectedLayer
66
} from "@reearth/beta/features/Editor/hooks/useLayers";
7-
import {
8-
GeoJsonFeatureUpdateProps
9-
} from "@reearth/beta/features/Editor/hooks/useSketch";
7+
import { GeoJsonFeatureUpdateProps } from "@reearth/beta/features/Editor/hooks/useSketch";
108
import { TabItem, Tabs } from "@reearth/beta/lib/reearth-ui";
119
import { ComputedFeature, Geometry } from "@reearth/core";
1210
import { NLSLayer, SketchFeature } from "@reearth/services/api/layersApi/utils";
@@ -18,6 +16,7 @@ import DataSource from "./DataSource";
1816
import FeatureInspector from "./FeatureInspector";
1917
import InfoboxSettings from "./InfoboxSettings";
2018
import LayerStyle from "./LayerStyle";
19+
import PhotoOverlaySettings from "./PhotoOverlaySettings";
2120

2221
const LAYER_INSPECTOR_TAB_STORAGE_KEY =
2322
"reearth-visualizer-map-layer-inspector-tab";
@@ -53,8 +52,8 @@ const InspectorTabs: FC<Props> = ({
5352
}) => {
5453
const t = useT();
5554

56-
const tabItems: TabItem[] = useMemo(
57-
() => [
55+
const tabItems: TabItem[] = useMemo(() => {
56+
const tabs: TabItem[] = [
5857
{
5958
id: "dataSource",
6059
icon: "data",
@@ -109,20 +108,36 @@ const InspectorTabs: FC<Props> = ({
109108
/>
110109
)
111110
}
112-
],
113-
[
114-
t,
115-
selectedLayer?.layer,
116-
onLayerNameUpdate,
117-
onLayerConfigUpdate,
118-
selectedFeature,
119-
selectedSketchFeature,
120-
onGeoJsonFeatureUpdate,
121-
layerStyles,
122-
layers,
123-
sceneId
124-
]
125-
);
111+
];
112+
113+
if (selectedLayer?.layer?.isSketch) {
114+
tabs.push({
115+
id: "photoOverlaySettings",
116+
icon: "image",
117+
placement: "left",
118+
tooltipText: t("Photo Overlay"),
119+
children: (
120+
<PhotoOverlaySettings
121+
selectedLayerId={selectedLayer.layer.id}
122+
photoOverlay={selectedLayer.layer?.photoOverlay}
123+
/>
124+
)
125+
});
126+
}
127+
128+
return tabs;
129+
}, [
130+
t,
131+
selectedLayer?.layer,
132+
onLayerNameUpdate,
133+
onLayerConfigUpdate,
134+
selectedFeature,
135+
selectedSketchFeature,
136+
onGeoJsonFeatureUpdate,
137+
layerStyles,
138+
layers,
139+
sceneId
140+
]);
126141

127142
const [currentTab, setCurrentTab] = useState(
128143
localStorage.getItem(LAYER_INSPECTOR_TAB_STORAGE_KEY) ?? "dataSource"

web/src/beta/features/Editor/Visualizer/hooks.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ import {
77
sceneProperty2ViewerPropertyMapping
88
} from "@reearth/beta/utils/convert-object";
99
import { Camera } from "@reearth/beta/utils/value";
10-
import type {
11-
LatLng,
12-
ComputedLayer,
13-
ComputedFeature,
14-
} from "@reearth/core";
10+
import type { LatLng, ComputedLayer, ComputedFeature } from "@reearth/core";
1511
import {
1612
useLayersFetcher,
1713
useSceneFetcher,
@@ -34,7 +30,10 @@ import {
3430

3531
import { useCurrentCamera } from "../atoms";
3632
import type { LayerSelectProps, SelectedLayer } from "../hooks/useLayers";
37-
import { PhotoOverlayPreviewAtom, SketchFeatureTooltipAtom } from "../Map/state";
33+
import {
34+
PhotoOverlayPreviewAtom,
35+
SketchFeatureTooltipAtom
36+
} from "../Map/state";
3837

3938
import { convertWidgets, processLayers, processProperty } from "./convert";
4039
import { convertStory } from "./convert-story";
@@ -193,7 +192,6 @@ export default ({
193192
visible: true
194193
}));
195194
}, [nlsLayers, layerStyles, infoboxBlockNames, showStoryPanel]);
196-
197195
const handleCoreLayerSelect = useCallback(
198196
(
199197
layerId?: string,

web/src/beta/features/Editor/hooks/useLayers.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -206,25 +206,25 @@ export default function ({
206206
[nlsLayers, selectedLayer, handleLayerSelect, useRemoveNLSLayer]
207207
);
208208

209-
const selectedFeature: SelectedFeature | undefined = useMemo(() => {
210-
if (!selectedLayer?.computedFeature?.id) return;
211-
const { id, geometry, properties } =
212-
selectedLayer.layer?.config?.data?.type === "3dtiles" ||
213-
selectedLayer.layer?.config?.data?.type === "osm-buildings" ||
214-
selectedLayer.layer?.config?.data?.type === "google-photorealistic" ||
215-
selectedLayer.layer?.config?.data?.type === "mvt"
216-
? selectedLayer.computedFeature
217-
: (selectedLayer.computedLayer?.features?.find(
218-
(f) => f.id === selectedLayer.computedFeature?.id
219-
) ?? {});
220-
221-
if (!id) return;
222-
return {
223-
id,
224-
geometry,
225-
properties
226-
};
227-
}, [selectedLayer]);
209+
const selectedFeature: SelectedFeature | undefined = useMemo(() => {
210+
if (!selectedLayer?.computedFeature?.id) return;
211+
const { id, geometry, properties } =
212+
selectedLayer.layer?.config?.data?.type === "3dtiles" ||
213+
selectedLayer.layer?.config?.data?.type === "osm-buildings" ||
214+
selectedLayer.layer?.config?.data?.type === "google-photorealistic" ||
215+
selectedLayer.layer?.config?.data?.type === "mvt"
216+
? selectedLayer.computedFeature
217+
: (selectedLayer.computedLayer?.features?.find(
218+
(f) => f.id === selectedLayer.computedFeature?.id
219+
) ?? {});
220+
221+
if (!id) return;
222+
return {
223+
id,
224+
geometry,
225+
properties
226+
};
227+
}, [selectedLayer]);
228228

229229
const handleLayerAdd = useCallback(
230230
async (inp: LayerAddProps) => {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { NLSLayer } from "@reearth/services/api/layersApi/utils";
2+
3+
import { PublishedNLSLayer } from "./types";
4+
5+
export const convertNLSLayers = (
6+
layers: PublishedNLSLayer[] | undefined
7+
): NLSLayer[] | undefined => {
8+
if (!layers) {
9+
return;
10+
}
11+
12+
return layers.map((l) => ({
13+
id: l.id,
14+
title: l.title,
15+
visible: !!l.isVisible,
16+
layerType: l.layerType,
17+
config: l.config,
18+
isSketch: l.isSketch,
19+
infobox: l.nlsInfobox,
20+
photoOverlay: l.nlsPhotoOverlay
21+
? {
22+
processedProperty: {
23+
enabled: l.nlsPhotoOverlay.property?.default?.enabled,
24+
cameraDuration: l.nlsPhotoOverlay.property?.default?.cameraDuration
25+
}
26+
}
27+
: undefined
28+
}));
29+
};

web/src/beta/features/Published/hooks.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { WidgetThemeOptions } from "../Visualizer/Crust/theme";
2020

2121
import { processProperty } from "./convert";
2222
import { processLayers, processNewProperty } from "./convert-new-property";
23+
import { convertNLSLayers } from "./convert-nls-layers";
2324
import { useGA } from "./googleAnalytics/useGA";
2425
import type {
2526
PublishedData,
@@ -256,6 +257,11 @@ export default (alias?: string) => {
256257
}));
257258
}, [data?.nlsLayers, data?.layerStyles, story]);
258259

260+
const nlsLayers = useMemo(
261+
() => convertNLSLayers(data?.nlsLayers),
262+
[data?.nlsLayers]
263+
);
264+
259265
useEffect(() => {
260266
const url = dataUrl(actualAlias);
261267
(async () => {
@@ -308,6 +314,7 @@ export default (alias?: string) => {
308314
viewerProperty,
309315
pluginProperty,
310316
layers,
317+
nlsLayers,
311318
widgets,
312319
widgetThemeOptions,
313320
story,

web/src/beta/features/Published/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default function Published({ alias }: Props) {
1212
viewerProperty,
1313
pluginProperty,
1414
layers,
15+
nlsLayers,
1516
widgets,
1617
widgetThemeOptions,
1718
story,
@@ -34,6 +35,7 @@ export default function Published({ alias }: Props) {
3435
isBuilt
3536
ready={ready}
3637
layers={layers}
38+
nlsLayers={nlsLayers}
3739
widgets={widgets}
3840
widgetThemeOptions={widgetThemeOptions}
3941
story={story}

0 commit comments

Comments
 (0)