Skip to content

Commit 70e52db

Browse files
refactor(web): disable tile opacity controls when Google Map tiles are present[VIZ-DEV-71] (#167)
Co-authored-by: lby <icesunex@hotmail.com>
1 parent 80e84c2 commit 70e52db

8 files changed

Lines changed: 87 additions & 4 deletions

File tree

web/src/classic/components/molecules/EarthEditor/PropertyPane/PropertyField/SliderField/index.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ const SliderField: React.FC<Props> = ({
136136
max={max}
137137
step={calculatedStep}
138138
marks={opacityMarkers}
139+
disabled={disabled}
139140
onAfterChange={onChange}
140141
onChange={handleSliderChange}
141142
dotStyle={{ display: "none" }}
@@ -208,14 +209,20 @@ const StyledInput = styled.input<InputProps>`
208209
}
209210
`;
210211

211-
const StyledSlider = styled(RCSlider)`
212+
const StyledSlider = styled(RCSlider)<{ disabled?: boolean }>`
212213
.rc-slider-mark-text {
213214
color: ${({ theme }) => theme.classic.properties.text};
214215
}
215216
216217
.rc-slider-mark-text-active {
217218
color: ${({ theme }) => theme.classic.text.pale};
218219
}
220+
221+
&.rc-slider-disabled {
222+
background-color: transparent;
223+
opacity: ${({ disabled }) => (disabled ? 0.6 : 1)};
224+
cursor: ${({ disabled }) => (disabled ? "not-allowed" : "inherit")};
225+
}
219226
`;
220227

221228
export default SliderField;

web/src/classic/components/molecules/EarthEditor/PropertyPane/PropertyField/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export type SchemaField<T extends ValueType = ValueType> = {
4646
suffix?: string;
4747
name?: string;
4848
description?: string;
49+
disabled?: boolean;
4950
isLinkable?: boolean;
5051
isTemplate?: boolean;
5152
ui?:
@@ -92,6 +93,7 @@ export type Props<T extends ValueType = ValueType> = {
9293
linkedDatasetSchemaId?: string;
9394
linkedDatasetId?: string;
9495
hidden?: boolean;
96+
disabled?: boolean;
9597
isLinkable?: boolean;
9698
isTemplate?: boolean;
9799
isCapturing?: boolean;
@@ -116,6 +118,7 @@ const PropertyField: React.FC<Props> = ({
116118
onUploadFile,
117119
onRemoveFile,
118120
hidden,
121+
disabled,
119122
isCapturing,
120123
onIsCapturingChange,
121124
camera,
@@ -147,6 +150,7 @@ const PropertyField: React.FC<Props> = ({
147150
!!field?.link || (isTemplate && !!field?.value) || (!!field?.mergedValue && !field?.value),
148151
linkedFieldName: field?.id,
149152
overridden: !!field?.overridden,
153+
disabled,
150154
value: field?.mergedValue ?? field?.value ?? schema?.defaultValue,
151155
onChange: useCallback(
152156
(value: ValueTypes[keyof ValueTypes] | undefined) => {

web/src/classic/components/molecules/EarthEditor/PropertyPane/PropertyItem/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ const PropertyItem: React.FC<Props> = ({
208208
.filter((g): g is PropertyListItem => !!g),
209209
[groups, layerMode, item],
210210
);
211+
211212
const schemaFields = useMemo(
212213
() =>
213214
selectedItem
@@ -226,11 +227,13 @@ const PropertyItem: React.FC<Props> = ({
226227
condf?.mergedValue ??
227228
condsf?.defaultValue ??
228229
(condsf?.type ? zeroValues[condsf.type] : undefined);
230+
229231
return {
230232
schemaField: f,
231233
field,
232234
events,
233235
hidden: f.only && (!condv || condv !== f.only.value),
236+
disabled: !!f.disabled,
234237
};
235238
})
236239
: [],
@@ -315,6 +318,7 @@ const PropertyItem: React.FC<Props> = ({
315318
field={f.field}
316319
schema={f.schemaField}
317320
hidden={f.hidden}
321+
disabled={f.disabled}
318322
isTemplate={isTemplate}
319323
{...f.events}
320324
{...props}

web/src/classic/components/molecules/Visualizer/hooks.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,34 @@ export default ({
126126
//
127127
// Terrain:
128128
// - terrainType "cesium" → "reearth_terrain"
129-
const overriddenSceneProperty = useMemo(
129+
const fallbackAppliedSceneProperty = useMemo(
130130
() => applyFallbacks(backwardCompatibleSceneProperty),
131131
[backwardCompatibleSceneProperty],
132132
);
133133

134+
// Step 3b: Override tile opacity for Google Map tiles (google_satellite, google_roadmap)
135+
// Google Maps API does not support opacity — force tile_opacity to 1 to avoid rendering issues.
136+
const overriddenSceneProperty = useMemo(() => {
137+
const tiles = fallbackAppliedSceneProperty?.tiles;
138+
if (!tiles) return fallbackAppliedSceneProperty;
139+
140+
const hasGoogleMapTiles = tiles.some(
141+
tile =>
142+
["google_satellite", "google_roadmap"].includes(tile.tile_type ?? "") &&
143+
tile.tile_opacity !== 1,
144+
);
145+
146+
if (!hasGoogleMapTiles) return fallbackAppliedSceneProperty;
147+
148+
return {
149+
...fallbackAppliedSceneProperty,
150+
tiles: tiles.map(tile => ({
151+
...tile,
152+
tile_opacity: 1,
153+
})),
154+
};
155+
}, [fallbackAppliedSceneProperty]);
156+
134157
// Step 4: Apply layer fallbacks when Cesium Ion token is not available
135158
// Data flow: rootLayer → (backward compatibility - not needed) → fallbacks → consumers
136159
// Fallback rules (only when no Cesium Ion token):

web/src/classic/components/organisms/EarthEditor/PropertyPane/convert.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,32 @@ const toUi = (ui: PropertySchemaFieldUi | null | undefined): SchemaField["ui"] =
232232
return undefined;
233233
};
234234

235+
const GOOGLE_MAP_TILE_TYPES = ["google_satellite", "google_roadmap"];
236+
237+
export const withGoogleMapTileOpacityDisabled = (
238+
items: Item[] | undefined,
239+
disabledDescription: string,
240+
): Item[] | undefined => {
241+
if (!items) return items;
242+
return items.map(item => {
243+
if (!("items" in item)) return item;
244+
const tileTypeSchemaField = item.schemaFields.find(f => f.id === "tile_type");
245+
const hasGoogleMapTile = item.items.some(listItem => {
246+
const tileTypeField = listItem.fields.find(f => f.id === "tile_type");
247+
const value =
248+
tileTypeField?.value ?? tileTypeField?.mergedValue ?? tileTypeSchemaField?.defaultValue;
249+
return typeof value === "string" && GOOGLE_MAP_TILE_TYPES.includes(value);
250+
});
251+
if (!hasGoogleMapTile) return item;
252+
return {
253+
...item,
254+
schemaFields: item.schemaFields.map(f =>
255+
f.id === "tile_opacity" ? { ...f, disabled: true, description: disabledDescription } : f,
256+
),
257+
};
258+
});
259+
};
260+
235261
export const convertLinkableDatasets = (
236262
data?: GetLinkableDatasetsQuery,
237263
): DatasetSchema[] | undefined => {

web/src/classic/components/organisms/EarthEditor/PropertyPane/hooks-queries.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@ import {
66
useGetLinkableDatasetsQuery,
77
useGetLayersFromLayerIdQuery,
88
} from "@reearth/classic/gql";
9+
import { useT } from "@reearth/services/i18n";
910
import { Selected } from "@reearth/services/state";
1011

11-
import { convert, Pane, convertLinkableDatasets, convertLayers } from "./convert";
12+
import {
13+
convert,
14+
Pane,
15+
convertLinkableDatasets,
16+
convertLayers,
17+
withGoogleMapTileOpacityDisabled,
18+
} from "./convert";
1219

1320
export type Mode = "infobox" | "scene" | "layer" | "block" | "widgets" | "widget" | "cluster";
1421

@@ -94,7 +101,17 @@ export default ({
94101
const propertyId = property?.id;
95102
const mergedProperty = layerMergedProperty ?? infoboxMergedProperty ?? blockMergedProperty;
96103

97-
const items = useMemo(() => convert(property, mergedProperty), [property, mergedProperty]);
104+
const t = useT();
105+
const items = useMemo(
106+
() =>
107+
withGoogleMapTileOpacityDisabled(
108+
convert(property, mergedProperty),
109+
t(
110+
"Disabled: Opacity adjustments are not available when Google Maps tiles are present, to comply with Google Maps Map Tiles API Policies.",
111+
),
112+
),
113+
[property, mergedProperty, t],
114+
);
98115

99116
const loading = scenePropertyLoading || layerPropertyLoading || layerLoading;
100117
const error = scenePropertyError ?? layerPropertyError ?? layerError;

web/src/services/i18n/translations/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ No selectable items: No selectable items
449449
Font family: Font family
450450
Font size: Font size
451451
Field set: Field set
452+
'Disabled: Opacity adjustments are not available when Google Maps tiles are present, to comply with Google Maps Map Tiles API Policies.': 'Disabled: Opacity adjustments are not available when Google Maps tiles are present, to comply with Google Maps Map Tiles API Policies.'
452453
Basic: Basic
453454
Template: Template
454455
template: template

web/src/services/i18n/translations/ja.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ No selectable items: 選択可能なアイテムがありません
416416
Font family: フォント
417417
Font size: サイズ
418418
Field set: 設定
419+
'Disabled: Opacity adjustments are not available when Google Maps tiles are present, to comply with Google Maps Map Tiles API Policies.': '無効:Google マップのタイルが存在する場合、Google マップ タイル API ポリシーに準拠するため、不透明度の調整はご利用いただけません。'
419420
Basic: インフォボックス
420421
Template: テンプレート
421422
template: テンプレート

0 commit comments

Comments
 (0)