feat(tgu-ops-ui): OSM tiles, editor layout fixes, map resizer
Карта: - Заменить схематичные контуры континентов на тайлы CartoDB Dark (dark_nolabels, CC BY 3.0, без API-ключа) через модульный кеш tileLoader.ts + отрисовщик drawTiles.ts на существующей Web Mercator проекции — без новых зависимостей - Сохранить сетку lat/lon 30° поверх тайлов (полезна для орбитального анализа), убрать нарисованные контуры и градиент океана - Обновить атрибуцию: © OpenStreetMap contributors · © CARTO Вкладка Редактор — раскладка: - Исправить цепочку высот: workspace переведён с display:grid на display:flex + flex-direction:column; layout получает flex:1 — единственный надёжный способ пробросить definite height через несколько вложенных grid-контейнеров в Chrome - Обернуть условные notice/applyError в постоянный div.tgu-editor-notices, чтобы .tgu-editor-layout всегда был третьим flex-ребёнком (раньше при отсутствии уведомлений попадал во вторую auto-строку grid и схлопывался) Вкладка Редактор — карта: - Добавить перетаскиваемый разделитель между картой и таймлайном: mapRatio state (по умолчанию 50/50), drag-хендлер через document events, ограничение 15–80%, визуальный индикатор .tgu-editor-map-resizer - Ограничить окно наземной трассы 24ч (720 точек, шаг 2 мин) независимо от зума таймлайна — при широком диапазоне (7 суток) шаг был 38 мин, трасса выглядела как хаотическая сетка через весь глобус Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo, useRef, useState, type MutableRefObject } from "react";
|
||||
import { useEffect, useMemo, useRef, useState, useCallback, type MutableRefObject } from "react";
|
||||
import { groundTrack, stationPasses, targetPasses } from "../tgu-map-2d/geometry/passes";
|
||||
import { Tgu2DMapView } from "../tgu-map-2d/Tgu2DMapView";
|
||||
import type { Tgu2DMapLayersState } from "../tgu-map-2d/model/mapLayerTypes";
|
||||
@@ -47,6 +47,8 @@ const EDITOR_MAP_LAYERS: Tgu2DMapLayersState = {
|
||||
export function TguEditorTab({ selectedSpacecraftId, selectedPlan, appliedRange, platforms }: TguEditorTabProps) {
|
||||
const idCounterRef = useRef(0);
|
||||
const targetCounterRef = useRef(0);
|
||||
const centerRef = useRef<HTMLElement>(null);
|
||||
const [mapRatio, setMapRatio] = useState(0.5);
|
||||
const [history, setHistory] = useState<DraftHistory>(() => ({
|
||||
draft: seedDraft(selectedPlan, selectedSpacecraftId),
|
||||
past: [],
|
||||
@@ -213,6 +215,27 @@ export function TguEditorTab({ selectedSpacecraftId, selectedPlan, appliedRange,
|
||||
});
|
||||
};
|
||||
|
||||
const handleResizerDown = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
const startY = e.clientY;
|
||||
const startRatio = mapRatio;
|
||||
|
||||
const onMove = (ev: MouseEvent) => {
|
||||
const el = centerRef.current;
|
||||
if (!el) return;
|
||||
const dy = ev.clientY - startY;
|
||||
setMapRatio(Math.max(0.15, Math.min(0.80, startRatio + dy / el.clientHeight)));
|
||||
};
|
||||
|
||||
const onUp = () => {
|
||||
document.removeEventListener("mousemove", onMove);
|
||||
document.removeEventListener("mouseup", onUp);
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", onMove);
|
||||
document.addEventListener("mouseup", onUp);
|
||||
}, [mapRatio]);
|
||||
|
||||
if (!selectedSpacecraftId && !selectedPlan) {
|
||||
return (
|
||||
<main className="tgu-editor-workspace">
|
||||
@@ -249,8 +272,10 @@ export function TguEditorTab({ selectedSpacecraftId, selectedPlan, appliedRange,
|
||||
onPan={pan}
|
||||
/>
|
||||
|
||||
{notice && <div className="tgu-alert tgu-alert--success tgu-editor-notice">{notice}</div>}
|
||||
{applyError && <div className="tgu-alert tgu-alert--danger tgu-editor-notice">{applyError}</div>}
|
||||
<div className="tgu-editor-notices">
|
||||
{notice && <div className="tgu-alert tgu-alert--success tgu-editor-notice">{notice}</div>}
|
||||
{applyError && <div className="tgu-alert tgu-alert--danger tgu-editor-notice">{applyError}</div>}
|
||||
</div>
|
||||
|
||||
<div className="tgu-editor-layout" style={{ gridTemplateColumns: rightMode === "none" ? "15.5rem minmax(0, 1fr) 0" : "15.5rem minmax(0, 1fr) 21rem" }}>
|
||||
<EditorRail
|
||||
@@ -273,7 +298,11 @@ export function TguEditorTab({ selectedSpacecraftId, selectedPlan, appliedRange,
|
||||
}}
|
||||
/>
|
||||
|
||||
<section className="tgu-editor-center">
|
||||
<section
|
||||
className="tgu-editor-center"
|
||||
ref={centerRef}
|
||||
style={{ gridTemplateRows: `${(mapRatio * 100).toFixed(1)}% minmax(0, 1fr)` }}
|
||||
>
|
||||
<div className="tgu-editor-map-stage">
|
||||
{rightMode === "shoot" && <div className="tgu-map-overlay">Кликните точку съёмки на карте.</div>}
|
||||
<Tgu2DMapView
|
||||
@@ -296,6 +325,7 @@ export function TguEditorTab({ selectedSpacecraftId, selectedPlan, appliedRange,
|
||||
}}
|
||||
onObjectSelect={() => undefined}
|
||||
/>
|
||||
<div className="tgu-editor-map-resizer" onMouseDown={handleResizerDown} />
|
||||
</div>
|
||||
<EditorTimeline
|
||||
activeLabel={activeLabel}
|
||||
@@ -470,13 +500,21 @@ function buildVisibilityTracks(
|
||||
return tracks;
|
||||
}
|
||||
|
||||
const MAP_TRACK_WINDOW_MS = 24 * 60 * 60 * 1000;
|
||||
const MAP_TRACK_POINTS = 720; // 2-minute step over 24h → ~45 points per LEO orbit
|
||||
|
||||
function buildEditorMapScene(
|
||||
spacecraftId: string | undefined,
|
||||
window: EditorTimelineWindow,
|
||||
stations: EditorGroundStation[]
|
||||
): Tgu2DMapScene {
|
||||
// Always show 24h of ground track centred on the timeline window,
|
||||
// regardless of how wide the timeline is zoomed out.
|
||||
const center = (window.fromMs + window.toMs) / 2;
|
||||
const mapRange = { fromMs: center - MAP_TRACK_WINDOW_MS / 2, toMs: center + MAP_TRACK_WINDOW_MS / 2 };
|
||||
|
||||
const lines = spacecraftId
|
||||
? groundTrack({ spacecraftId }, { fromMs: window.fromMs, toMs: window.toMs }, 260).map((points, index) => ({
|
||||
? groundTrack({ spacecraftId }, mapRange, MAP_TRACK_POINTS).map((points, index) => ({
|
||||
id: `${spacecraftId}:track:${index}`,
|
||||
layer: "tracks" as const,
|
||||
points,
|
||||
|
||||
Reference in New Issue
Block a user