feat(map): add fixed ENU and WGS84 sector grid
This commit is contained in:
@@ -8,6 +8,8 @@ import type {
|
||||
MapGatewayHealth,
|
||||
MapPresentation,
|
||||
MapProviderStatus,
|
||||
GridLodProfile,
|
||||
GridSectorSelection,
|
||||
} from "./CesiumMapRenderer.js";
|
||||
import { mapRuntimeEntityId, useMapDataProductRuntime } from "./useMapDataProductRuntime.js";
|
||||
import {
|
||||
@@ -40,6 +42,8 @@ import {
|
||||
} from "./mapReferenceStations.js";
|
||||
import { useMapReferenceRuntime, useMapReferenceSearch } from "./useMapReferenceRuntime.js";
|
||||
import { buildMapSearchIndex, searchMapSubjects } from "./mapSearch.mjs";
|
||||
import { DEFAULT_GRID_LOD_PROFILES, gridLodProfile } from "./mapGridPolicy.mjs";
|
||||
import { MAX_LOCAL_GRID_INDEX } from "./mapSectorGrid.mjs";
|
||||
const CesiumMapRenderer = lazy(() => import("./CesiumMapRenderer.js").then((module) => ({ default: module.CesiumMapRenderer })));
|
||||
|
||||
type PreviewFeatures = { inspector?: boolean; toolbar?: boolean; assistant?: boolean };
|
||||
@@ -227,12 +231,13 @@ const initialMapSettings: MapPageSettings = {
|
||||
gridLodEnabled: true,
|
||||
grid3dEnabled: true,
|
||||
gridGraticuleEnabled: true,
|
||||
gridCenterMode: "camera",
|
||||
gridCenterMode: "fixed",
|
||||
gridCenterLatitude: 55.7558,
|
||||
gridCenterLongitude: 37.6173,
|
||||
gridTileSizeKm: 10,
|
||||
gridAutoDisableHeightKm: 10_000,
|
||||
gridRebuildOnMoveEnd: true,
|
||||
gridLegacyMode: false,
|
||||
gridMax3dViewAngleDegrees: 30,
|
||||
gridHeightMeters: 500,
|
||||
gridLod1MaxHeightKm: 10,
|
||||
@@ -241,31 +246,47 @@ const initialMapSettings: MapPageSettings = {
|
||||
gridLod2MaxHeightKm: 50,
|
||||
gridLod2StepKm: 5,
|
||||
gridLod2Mode: "3d",
|
||||
gridLod3MaxHeightKm: 180,
|
||||
gridLod3MaxHeightKm: 200,
|
||||
gridLod3StepKm: 25,
|
||||
gridLod3Mode: "3d",
|
||||
gridLod4MaxHeightKm: 700,
|
||||
gridLod4StepKm: 100,
|
||||
gridLod4MaxHeightKm: 800,
|
||||
gridLod4StepKm: 50,
|
||||
gridLod4Mode: "graticule",
|
||||
gridLod5StepKm: 500,
|
||||
gridLod5MaxHeightKm: 3_000,
|
||||
gridLod5StepKm: 50,
|
||||
gridLod5Mode: "graticule",
|
||||
gridRadiusKm: 1_000,
|
||||
gridLineWidth: 4,
|
||||
gridLineDiameterMeters: 10,
|
||||
gridColor: "#f5f5f5",
|
||||
gridRadiusKm: 40,
|
||||
gridLineWidth: 1,
|
||||
gridLineDiameterMeters: 7,
|
||||
gridColor: "#9c9c9c",
|
||||
gridOpacity: 12,
|
||||
gridDotsEnabled: true,
|
||||
gridDotsSize: 7,
|
||||
gridDotsDiameterMeters: 80,
|
||||
gridDotsColor: "#ffffff",
|
||||
gridDotsDiameterMeters: 10,
|
||||
gridDotsColor: "#9c9c9c",
|
||||
gridDotsOpacity: 58,
|
||||
gridCrossesEnabled: false,
|
||||
gridCrossesLengthMeters: 200,
|
||||
gridCrossesLengthMeters: 60,
|
||||
gridCrossesWidthMeters: 10,
|
||||
gridCrossesColor: "#35cfff",
|
||||
gridCrossesOpacity: 50,
|
||||
gridCrossesColor: "#9c9c9c",
|
||||
gridCrossesOpacity: 46,
|
||||
gridLodProfiles: structuredClone(DEFAULT_GRID_LOD_PROFILES) as GridLodProfile[],
|
||||
};
|
||||
|
||||
function resolveGridLodProfiles(settings?: Partial<MapPageSettings>): GridLodProfile[] {
|
||||
// A layout saved by the previous flat contract must not lose the values the
|
||||
// operator already tuned. Promote its common visual fields and per-band
|
||||
// height/step/mode values into five authoritative profiles on first read;
|
||||
// the next ordinary page save persists the canonical array.
|
||||
const legacySettings: MapPresentation = {
|
||||
...initialMapSettings,
|
||||
...settings,
|
||||
gridLodProfiles: Array.isArray(settings?.gridLodProfiles) ? settings.gridLodProfiles : [],
|
||||
cacheRefresh: false,
|
||||
};
|
||||
return Array.from({ length: 5 }, (_unused, index) => gridLodProfile(legacySettings, index) as GridLodProfile);
|
||||
}
|
||||
|
||||
// A valid, deterministic scene view is available before Cesium emits its
|
||||
// first move-end event. It makes the page contract immediately saveable;
|
||||
// the renderer replaces it with the exact live camera as soon as it is ready.
|
||||
@@ -389,6 +410,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
}>(function MapFixturePreview({ features = { inspector: true, toolbar: true, assistant: false }, expanded = false, initialLayout = null, applicationId, pageId }, ref) {
|
||||
const workspaceRef = useRef<HTMLDivElement>(null);
|
||||
const [selectedId, setSelectedId] = useState<string>();
|
||||
const [selectedGridSector, setSelectedGridSector] = useState<GridSectorSelection | null>(null);
|
||||
const [subjectCardOpen, setSubjectCardOpen] = useState(false);
|
||||
const [subjectCardRect, setSubjectCardRect] = useState<WorkspaceWindowRect>(defaultSubjectCardRect);
|
||||
const [subjectCardMaximized, setSubjectCardMaximized] = useState(false);
|
||||
@@ -419,7 +441,13 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
// Layouts saved before the cache policy field existed retain the safe
|
||||
// append-only default when they are opened again.
|
||||
cacheNoOverwrite: initialLayout?.settings?.cacheNoOverwrite ?? true,
|
||||
// Camera-relative layouts were decorative and had no stable sector
|
||||
// identity. Opening one performs a deterministic migration to its stored
|
||||
// Moscow origin; the current viewport is never promoted to definition.
|
||||
gridCenterMode: "fixed",
|
||||
gridLodProfiles: resolveGridLodProfiles(initialLayout?.settings),
|
||||
}));
|
||||
const [selectedGridLod, setSelectedGridLod] = useState("0");
|
||||
const [mapHeight, setMapHeight] = useState(() => initialLayout?.mapHeight ?? (expanded ? 620 : 470));
|
||||
const [mapCamera, setMapCamera] = useState<MapCameraView>(initialLayout?.camera ?? fallbackMapCamera);
|
||||
const mapRendererRef = useRef<CesiumMapRendererHandle | null>(null);
|
||||
@@ -646,6 +674,19 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
[cacheRefresh, mapSettings],
|
||||
);
|
||||
const updateMapSettings = (patch: Partial<MapPageSettings>) => setMapSettings((current) => ({ ...current, ...patch }));
|
||||
const selectedGridLodIndex = Math.max(0, Math.min(4, Number.parseInt(selectedGridLod, 10) || 0));
|
||||
const activeGridLod = mapSettings.gridLodProfiles[selectedGridLodIndex] ?? DEFAULT_GRID_LOD_PROFILES[selectedGridLodIndex];
|
||||
const minimumGridLodHeight = selectedGridLodIndex === 0
|
||||
? 0.1
|
||||
: mapSettings.gridLodProfiles[selectedGridLodIndex - 1].maxHeightKm + 0.1;
|
||||
const maximumGridLodHeight = selectedGridLodIndex === mapSettings.gridLodProfiles.length - 1
|
||||
? 20_000
|
||||
: Math.max(minimumGridLodHeight, mapSettings.gridLodProfiles[selectedGridLodIndex + 1].maxHeightKm - 0.1);
|
||||
const updateGridLod = (patch: Partial<GridLodProfile>) => updateMapSettings({
|
||||
gridLodProfiles: mapSettings.gridLodProfiles.map((profile, index) => (
|
||||
index === selectedGridLodIndex ? { ...profile, ...patch } : profile
|
||||
)),
|
||||
});
|
||||
const setCacheEnabled = (cacheEnabled: boolean) => {
|
||||
updateMapSettings({ cacheEnabled });
|
||||
setRendererRevision((value) => value + 1);
|
||||
@@ -1267,57 +1308,47 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
description: "first adapter control",
|
||||
group: "Слои",
|
||||
content: <>
|
||||
<small className="catalog-map-inspector__note">Пять LOD сохраняют пространственную сетку вблизи и переходят к гратикуле на дальних высотах. Новый слой подготавливается до удаления предыдущего.</small>
|
||||
<small className="catalog-map-inspector__note">Фиксированная московская ENU-адресация задаёт неизменные сектора на LOD 1–3. LOD 4–5 используют глобальную WGS84-гратику́лу; камера выбирает только LOD и видимую область.</small>
|
||||
<Checker checked={mapSettings.gridVisible} label="Сетка" onChange={(gridVisible) => updateMapSettings({ gridVisible })} />
|
||||
<Checker checked={mapSettings.grid3dEnabled} label="3D-сетка" onChange={(grid3dEnabled) => updateMapSettings({ grid3dEnabled })} />
|
||||
<Checker checked={mapSettings.gridGraticuleEnabled} label="Гратикула" onChange={(gridGraticuleEnabled) => updateMapSettings({ gridGraticuleEnabled })} />
|
||||
<Checker checked={mapSettings.gridLodEnabled} label="LOD по высоте камеры" onChange={(gridLodEnabled) => updateMapSettings({ gridLodEnabled })} />
|
||||
<Checker checked={mapSettings.gridRebuildOnMoveEnd} label="Перестраивать после движения" onChange={(gridRebuildOnMoveEnd) => updateMapSettings({ gridRebuildOnMoveEnd })} />
|
||||
<InspectorSelectField
|
||||
label="Центр сетки"
|
||||
value={mapSettings.gridCenterMode}
|
||||
options={[
|
||||
{ value: "camera", label: "За камерой", description: "Центр следует за viewport по стабильным тайлам" },
|
||||
{ value: "fixed", label: "Фиксированный", description: "Используются заданные координаты" },
|
||||
]}
|
||||
onChange={(gridCenterMode) => updateMapSettings({ gridCenterMode })}
|
||||
/>
|
||||
{mapSettings.gridCenterMode === "fixed" ? <>
|
||||
<RangeControl label="Центр: широта" value={mapSettings.gridCenterLatitude} min={-89.999} max={89.999} step={0.0001} formatValue={(value) => value.toFixed(4)} onChange={(gridCenterLatitude) => updateMapSettings({ gridCenterLatitude })} />
|
||||
<RangeControl label="Центр: долгота" value={mapSettings.gridCenterLongitude} min={-180} max={180} step={0.0001} formatValue={(value) => value.toFixed(4)} onChange={(gridCenterLongitude) => updateMapSettings({ gridCenterLongitude })} />
|
||||
</> : null}
|
||||
<RangeControl label="Размер тайла" value={mapSettings.gridTileSizeKm} min={1} max={500} step={1} formatValue={(value) => `${value} км`} onChange={(gridTileSizeKm) => updateMapSettings({ gridTileSizeKm })} />
|
||||
<ControlRow label="Система координат"><strong>Fixed ENU · WGS84</strong></ControlRow>
|
||||
<RangeControl label="Origin: широта" value={mapSettings.gridCenterLatitude} min={-89.9} max={89.9} step={0.000001} formatValue={(value) => value.toFixed(6)} onChange={(gridCenterLatitude) => updateMapSettings({ gridCenterLatitude })} />
|
||||
<RangeControl label="Origin: долгота" value={mapSettings.gridCenterLongitude} min={-180} max={180} step={0.000001} formatValue={(value) => value.toFixed(6)} onChange={(gridCenterLongitude) => updateMapSettings({ gridCenterLongitude })} />
|
||||
<RangeControl label="Автовыключение выше" value={mapSettings.gridAutoDisableHeightKm} min={0} max={50_000} step={100} formatValue={(value) => value === 0 ? "выкл" : `${value} км`} onChange={(gridAutoDisableHeightKm) => updateMapSettings({ gridAutoDisableHeightKm })} />
|
||||
<RangeControl label="Высота над поверхностью" value={mapSettings.gridHeightMeters} min={0} max={1000} formatValue={(value) => `${value} м`} onChange={(gridHeightMeters) => updateMapSettings({ gridHeightMeters })} />
|
||||
<RangeControl label="Макс. угол обзора 3D" value={mapSettings.gridMax3dViewAngleDegrees} min={0} max={89} step={1} formatValue={(value) => `${value}°`} onChange={(gridMax3dViewAngleDegrees) => updateMapSettings({ gridMax3dViewAngleDegrees })} />
|
||||
<InspectorSelectField label="LOD 1: режим" value={mapSettings.gridLod1Mode} options={GRID_MODE_OPTIONS} onChange={(gridLod1Mode) => updateMapSettings({ gridLod1Mode })} />
|
||||
<RangeControl label="LOD 1: до высоты" value={mapSettings.gridLod1MaxHeightKm} min={1} max={50} formatValue={(value) => `${value} км`} onChange={(gridLod1MaxHeightKm) => updateMapSettings({ gridLod1MaxHeightKm })} />
|
||||
<RangeControl label="LOD 1: шаг" value={mapSettings.gridLod1StepKm} min={1} max={10} formatValue={(value) => `${value} км`} onChange={(gridLod1StepKm) => updateMapSettings({ gridLod1StepKm })} />
|
||||
<InspectorSelectField label="LOD 2: режим" value={mapSettings.gridLod2Mode} options={GRID_MODE_OPTIONS} onChange={(gridLod2Mode) => updateMapSettings({ gridLod2Mode })} />
|
||||
<RangeControl label="LOD 2: до высоты" value={mapSettings.gridLod2MaxHeightKm} min={10} max={200} formatValue={(value) => `${value} км`} onChange={(gridLod2MaxHeightKm) => updateMapSettings({ gridLod2MaxHeightKm })} />
|
||||
<RangeControl label="LOD 2: шаг" value={mapSettings.gridLod2StepKm} min={1} max={25} formatValue={(value) => `${value} км`} onChange={(gridLod2StepKm) => updateMapSettings({ gridLod2StepKm })} />
|
||||
<InspectorSelectField label="LOD 3: режим" value={mapSettings.gridLod3Mode} options={GRID_MODE_OPTIONS} onChange={(gridLod3Mode) => updateMapSettings({ gridLod3Mode })} />
|
||||
<RangeControl label="LOD 3: до высоты" value={mapSettings.gridLod3MaxHeightKm} min={50} max={1_000} step={10} formatValue={(value) => `${value} км`} onChange={(gridLod3MaxHeightKm) => updateMapSettings({ gridLod3MaxHeightKm })} />
|
||||
<RangeControl label="LOD 3: шаг" value={mapSettings.gridLod3StepKm} min={5} max={100} formatValue={(value) => `${value} км`} onChange={(gridLod3StepKm) => updateMapSettings({ gridLod3StepKm })} />
|
||||
<InspectorSelectField label="LOD 4: режим" value={mapSettings.gridLod4Mode} options={GRID_MODE_OPTIONS} onChange={(gridLod4Mode) => updateMapSettings({ gridLod4Mode })} />
|
||||
<RangeControl label="LOD 4: до высоты" value={mapSettings.gridLod4MaxHeightKm} min={100} max={5_000} step={50} formatValue={(value) => `${value} км`} onChange={(gridLod4MaxHeightKm) => updateMapSettings({ gridLod4MaxHeightKm })} />
|
||||
<RangeControl label="LOD 4: шаг" value={mapSettings.gridLod4StepKm} min={10} max={500} step={5} formatValue={(value) => `${value} км`} onChange={(gridLod4StepKm) => updateMapSettings({ gridLod4StepKm })} />
|
||||
<InspectorSelectField label="LOD 5: режим" value={mapSettings.gridLod5Mode} options={GRID_MODE_OPTIONS} onChange={(gridLod5Mode) => updateMapSettings({ gridLod5Mode })} />
|
||||
<RangeControl label="LOD 5: шаг" value={mapSettings.gridLod5StepKm} min={50} max={2_000} step={25} formatValue={(value) => `${value} км`} onChange={(gridLod5StepKm) => updateMapSettings({ gridLod5StepKm })} />
|
||||
<RangeControl label="Радиус видимости" value={mapSettings.gridRadiusKm} min={5} max={2_000} step={5} formatValue={(value) => `${value} км`} onChange={(gridRadiusKm) => updateMapSettings({ gridRadiusKm })} />
|
||||
<ControlRow label="Цвет линий"><ColorField label="Цвет линий сетки" value={mapSettings.gridColor} onChange={(gridColor) => updateMapSettings({ gridColor })} /></ControlRow>
|
||||
<RangeControl label="3D-линии: диаметр" value={mapSettings.gridLineDiameterMeters} min={1} max={100} step={1} formatValue={(value) => `${value} м`} onChange={(gridLineDiameterMeters) => updateMapSettings({ gridLineDiameterMeters })} />
|
||||
<RangeControl label="Гратикула: толщина" value={mapSettings.gridLineWidth} min={1} max={8} formatValue={(value) => `${value} px`} onChange={(gridLineWidth) => updateMapSettings({ gridLineWidth })} />
|
||||
<RangeControl label="Прозрачность сетки" value={mapSettings.gridOpacity} min={0} max={100} formatValue={(value) => `${value}%`} onChange={(gridOpacity) => updateMapSettings({ gridOpacity })} />
|
||||
<Checker checked={mapSettings.gridDotsEnabled} label="Кружки" onChange={(gridDotsEnabled) => updateMapSettings({ gridDotsEnabled })} />
|
||||
<RangeControl label="Кружки: диаметр" value={mapSettings.gridDotsDiameterMeters} min={2} max={1_000} step={2} formatValue={(value) => `${value} м`} onChange={(gridDotsDiameterMeters) => updateMapSettings({ gridDotsDiameterMeters })} />
|
||||
<ControlRow label="Кружки: цвет"><ColorField label="Цвет кружков сетки" value={mapSettings.gridDotsColor} onChange={(gridDotsColor) => updateMapSettings({ gridDotsColor })} /></ControlRow>
|
||||
<RangeControl label="Кружки: прозрачность" value={mapSettings.gridDotsOpacity} min={0} max={100} formatValue={(value) => `${value}%`} onChange={(gridDotsOpacity) => updateMapSettings({ gridDotsOpacity })} />
|
||||
<Checker checked={mapSettings.gridCrossesEnabled} label="Кресты" onChange={(gridCrossesEnabled) => updateMapSettings({ gridCrossesEnabled })} />
|
||||
<RangeControl label="Кресты: длина" value={mapSettings.gridCrossesLengthMeters} min={2} max={2_000} step={2} formatValue={(value) => `${value} м`} onChange={(gridCrossesLengthMeters) => updateMapSettings({ gridCrossesLengthMeters })} />
|
||||
<RangeControl label="Кресты: ширина" value={mapSettings.gridCrossesWidthMeters} min={1} max={100} step={1} formatValue={(value) => `${value} м`} onChange={(gridCrossesWidthMeters) => updateMapSettings({ gridCrossesWidthMeters })} />
|
||||
<ControlRow label="Кресты: цвет"><ColorField label="Цвет крестов сетки" value={mapSettings.gridCrossesColor} onChange={(gridCrossesColor) => updateMapSettings({ gridCrossesColor })} /></ControlRow>
|
||||
<RangeControl label="Кресты: прозрачность" value={mapSettings.gridCrossesOpacity} min={0} max={100} formatValue={(value) => `${value}%`} onChange={(gridCrossesOpacity) => updateMapSettings({ gridCrossesOpacity })} />
|
||||
<div className="catalog-map-grid-lod-tabs">
|
||||
<SegmentedControl value={selectedGridLod} items={DEFAULT_GRID_LOD_PROFILES.map((_profile, index) => ({ value: String(index), label: `LOD ${index + 1}` }))} label="Уровень детализации сетки" onChange={setSelectedGridLod} />
|
||||
</div>
|
||||
<RangeControl label={selectedGridLodIndex === 4 ? "Порог профиля" : "До высоты"} value={activeGridLod.maxHeightKm} min={minimumGridLodHeight} max={maximumGridLodHeight} step={0.1} formatValue={(value) => `${value} км`} onChange={(maxHeightKm) => updateGridLod({ maxHeightKm })} />
|
||||
{selectedGridLodIndex === 4 ? <small className="catalog-map-inspector__note">Последний LOD остаётся активным выше своего порога до общего автовыключения.</small> : null}
|
||||
<InspectorSelectField label="Режим" value={activeGridLod.mode} options={GRID_MODE_OPTIONS} onChange={(mode) => updateGridLod({ mode })} />
|
||||
<RangeControl label="Высота WGS84" value={activeGridLod.heightMeters} min={0} max={5_000} step={10} formatValue={(value) => `${value} м`} onChange={(heightMeters) => updateGridLod({ heightMeters })} />
|
||||
<RangeControl label="Конус видимости 3D" value={activeGridLod.max3dViewAngleDegrees} min={30} max={170} step={1} formatValue={(value) => `${value}°`} onChange={(max3dViewAngleDegrees) => updateGridLod({ max3dViewAngleDegrees })} />
|
||||
<RangeControl label="Шаг ENU-секторов" value={activeGridLod.stepKm} min={0.1} max={5_000} step={0.1} formatValue={(value) => `${value} км`} onChange={(stepKm) => updateGridLod({ stepKm, radiusKm: Math.min(activeGridLod.radiusKm, stepKm * MAX_LOCAL_GRID_INDEX) })} />
|
||||
<RangeControl label="Размер тайла ENU" value={activeGridLod.tileSizeKm} min={1} max={50} step={1} formatValue={(value) => `${value} км`} onChange={(tileSizeKm) => updateGridLod({ tileSizeKm })} />
|
||||
<RangeControl label="Радиус ENU-поля" value={activeGridLod.radiusKm} min={1} max={Math.min(100_000, activeGridLod.stepKm * MAX_LOCAL_GRID_INDEX)} step={1} formatValue={(value) => `${value} км`} onChange={(radiusKm) => updateGridLod({ radiusKm })} />
|
||||
<RangeControl label="Диаметр 3D-линий" value={activeGridLod.lineDiameterMeters} min={1} max={100} step={1} formatValue={(value) => `${value} м`} onChange={(lineDiameterMeters) => updateGridLod({ lineDiameterMeters })} />
|
||||
<ControlRow label="Цвет 3D-линий"><ColorField label="Цвет линий ENU-сетки" value={activeGridLod.lineColor} onChange={(lineColor) => updateGridLod({ lineColor })} /></ControlRow>
|
||||
<RangeControl label="Прозрачность 3D-линий" value={activeGridLod.lineOpacity} min={0} max={100} formatValue={(value) => `${value}%`} onChange={(lineOpacity) => updateGridLod({ lineOpacity })} />
|
||||
<Checker checked={activeGridLod.dotsEnabled} label="Кружки" onChange={(dotsEnabled) => updateGridLod({ dotsEnabled })} />
|
||||
<RangeControl label="Кружки: диаметр" value={activeGridLod.dotsDiameterMeters} min={1} max={1_000} step={1} formatValue={(value) => `${value} м`} onChange={(dotsDiameterMeters) => updateGridLod({ dotsDiameterMeters })} />
|
||||
<ControlRow label="Кружки: цвет"><ColorField label="Цвет кружков сетки" value={activeGridLod.dotsColor} onChange={(dotsColor) => updateGridLod({ dotsColor })} /></ControlRow>
|
||||
<RangeControl label="Кружки: прозрачность" value={activeGridLod.dotsOpacity} min={0} max={100} formatValue={(value) => `${value}%`} onChange={(dotsOpacity) => updateGridLod({ dotsOpacity })} />
|
||||
<Checker checked={activeGridLod.crossesEnabled} label="Кресты" onChange={(crossesEnabled) => updateGridLod({ crossesEnabled })} />
|
||||
<RangeControl label="Кресты: длина" value={activeGridLod.crossesLengthMeters} min={2} max={5_000} step={2} formatValue={(value) => `${value} м`} onChange={(crossesLengthMeters) => updateGridLod({ crossesLengthMeters })} />
|
||||
<RangeControl label="Кресты: ширина" value={activeGridLod.crossesWidthMeters} min={1} max={500} step={1} formatValue={(value) => `${value} м`} onChange={(crossesWidthMeters) => updateGridLod({ crossesWidthMeters })} />
|
||||
<ControlRow label="Кресты: цвет"><ColorField label="Цвет крестов сетки" value={activeGridLod.crossesColor} onChange={(crossesColor) => updateGridLod({ crossesColor })} /></ControlRow>
|
||||
<RangeControl label="Кресты: прозрачность" value={activeGridLod.crossesOpacity} min={0} max={100} formatValue={(value) => `${value}%`} onChange={(crossesOpacity) => updateGridLod({ crossesOpacity })} />
|
||||
<RangeControl label="Шаг гратикулы" value={activeGridLod.graticuleStepDegrees} min={0.1} max={10} step={0.05} formatValue={(value) => `${value}°`} onChange={(graticuleStepDegrees) => updateGridLod({ graticuleStepDegrees })} />
|
||||
<RangeControl label="Толщина гратикулы" value={activeGridLod.graticuleLineWidthPx} min={1} max={3} step={1} formatValue={(value) => `${value} px`} onChange={(graticuleLineWidthPx) => updateGridLod({ graticuleLineWidthPx })} />
|
||||
<ControlRow label="Цвет гратикулы"><ColorField label="Цвет WGS84-гратику́лы" value={activeGridLod.graticuleColor} onChange={(graticuleColor) => updateGridLod({ graticuleColor })} /></ControlRow>
|
||||
<RangeControl label="Прозрачность гратикулы" value={activeGridLod.graticuleOpacity} min={0} max={100} formatValue={(value) => `${value}%`} onChange={(graticuleOpacity) => updateGridLod({ graticuleOpacity })} />
|
||||
<ControlRow label="Выбранный сектор"><strong className="catalog-map-grid-sector-id">{selectedGridSector?.id ?? "Нажмите сектор на карте"}</strong></ControlRow>
|
||||
{selectedGridSector ? <small className="catalog-map-inspector__note">LOD {selectedGridSector.lod} · {selectedGridSector.units === "meters-enu"
|
||||
? `ENU ${selectedGridSector.bounds.west}…${selectedGridSector.bounds.east} м E; ${selectedGridSector.bounds.south}…${selectedGridSector.bounds.north} м N`
|
||||
: `WGS84 ${selectedGridSector.bounds.west}…${selectedGridSector.bounds.east}°; ${selectedGridSector.bounds.south}…${selectedGridSector.bounds.north}°`}</small> : null}
|
||||
</>,
|
||||
},
|
||||
{
|
||||
@@ -1447,6 +1478,7 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
|
||||
key={rendererRevision}
|
||||
ref={mapRendererRef}
|
||||
onSelect={handleSelect}
|
||||
onGridSectorSelect={setSelectedGridSector}
|
||||
onGatewayHealth={handleRendererGatewayHealth}
|
||||
onProviderStatus={setProviderStatus}
|
||||
onCameraChange={handleCameraChange}
|
||||
|
||||
Reference in New Issue
Block a user