fix: prevent hover update loop and map style ready guard
This commit is contained in:
부모
ea51aee6b4
커밋
ed5b0da5f9
@ -4,6 +4,7 @@ import { Map3DSettingsToggles } from "../../features/map3dSettings/Map3DSettings
|
||||
import type { MapToggleState } from "../../features/mapToggles/MapToggles";
|
||||
import { MapToggles } from "../../features/mapToggles/MapToggles";
|
||||
import { TypeFilterGrid } from "../../features/typeFilter/TypeFilterGrid";
|
||||
import type { DerivedLegacyVessel } from "../../features/legacyDashboard/model/types";
|
||||
import { useLegacyVessels } from "../../entities/legacyVessel/api/useLegacyVessels";
|
||||
import { buildLegacyVesselIndex } from "../../entities/legacyVessel/lib";
|
||||
import type { LegacyVesselIndex } from "../../entities/legacyVessel/lib";
|
||||
@ -87,6 +88,11 @@ export function DashboardPage() {
|
||||
});
|
||||
|
||||
const [selectedMmsi, setSelectedMmsi] = useState<number | null>(null);
|
||||
const [highlightedMmsiSet, setHighlightedMmsiSet] = useState<number[]>([]);
|
||||
const [hoveredMmsiSet, setHoveredMmsiSet] = useState<number[]>([]);
|
||||
const [hoveredFleetMmsiSet, setHoveredFleetMmsiSet] = useState<number[]>([]);
|
||||
const [hoveredPairMmsiSet, setHoveredPairMmsiSet] = useState<number[]>([]);
|
||||
const [hoveredFleetOwnerKey, setHoveredFleetOwnerKey] = useState<string | null>(null);
|
||||
const [typeEnabled, setTypeEnabled] = useState<Record<VesselTypeCode, boolean>>({
|
||||
PT: true,
|
||||
"PT-S": true,
|
||||
@ -109,6 +115,8 @@ export function DashboardPage() {
|
||||
fleetCircles: true,
|
||||
});
|
||||
|
||||
const [fleetFocus, setFleetFocus] = useState<{ id: string | number; center: [number, number]; zoom?: number } | undefined>(undefined);
|
||||
|
||||
const [settings, setSettings] = useState<Map3DSettings>({
|
||||
showShips: true,
|
||||
showDensity: false,
|
||||
@ -192,6 +200,52 @@ export function DashboardPage() {
|
||||
return legacyHits.get(selectedMmsi) ?? null;
|
||||
}, [selectedMmsi, legacyHits]);
|
||||
|
||||
const availableTargetMmsiSet = useMemo(
|
||||
() => new Set(targetsInScope.map((t) => t.mmsi).filter((mmsi) => Number.isFinite(mmsi))),
|
||||
[targetsInScope],
|
||||
);
|
||||
const activeHighlightedMmsiSet = useMemo(
|
||||
() => highlightedMmsiSet.filter((mmsi) => availableTargetMmsiSet.has(mmsi)),
|
||||
[highlightedMmsiSet, availableTargetMmsiSet],
|
||||
);
|
||||
|
||||
const setUniqueSorted = (items: number[]) =>
|
||||
Array.from(new Set(items.filter((item) => Number.isFinite(item)))).sort((a, b) => a - b);
|
||||
|
||||
const setSortedIfChanged = (next: number[]) => {
|
||||
const sorted = setUniqueSorted(next);
|
||||
return (prev: number[]) => (prev.length === sorted.length && prev.every((v, i) => v === sorted[i]) ? prev : sorted);
|
||||
};
|
||||
|
||||
const handleFleetContextMenu = (ownerKey: string, mmsis: number[]) => {
|
||||
if (!mmsis.length) return;
|
||||
const members = mmsis
|
||||
.map((mmsi) => legacyVesselsFiltered.find((v): v is DerivedLegacyVessel => v.mmsi === mmsi))
|
||||
.filter(
|
||||
(v): v is DerivedLegacyVessel & { lat: number; lon: number } =>
|
||||
v != null && typeof v.lat === "number" && typeof v.lon === "number" && Number.isFinite(v.lat) && Number.isFinite(v.lon),
|
||||
);
|
||||
|
||||
if (members.length === 0) return;
|
||||
const sumLon = members.reduce((acc, v) => acc + v.lon, 0);
|
||||
const sumLat = members.reduce((acc, v) => acc + v.lat, 0);
|
||||
const center: [number, number] = [sumLon / members.length, sumLat / members.length];
|
||||
setFleetFocus({
|
||||
id: `${ownerKey}-${Date.now()}`,
|
||||
center,
|
||||
zoom: 9,
|
||||
});
|
||||
};
|
||||
|
||||
const toggleHighlightedMmsi = (mmsi: number) => {
|
||||
setHighlightedMmsiSet((prev) => {
|
||||
const next = new Set(prev);
|
||||
if (next.has(mmsi)) next.delete(mmsi);
|
||||
else next.add(mmsi);
|
||||
return Array.from(next).sort((a, b) => a - b);
|
||||
});
|
||||
};
|
||||
|
||||
const fishingCount = legacyVesselsAll.filter((v) => v.state.isFishing).length;
|
||||
const transitCount = legacyVesselsAll.filter((v) => v.state.isTransit).length;
|
||||
|
||||
@ -304,6 +358,22 @@ export function DashboardPage() {
|
||||
vessels={legacyVesselsAll}
|
||||
fleetVessels={legacyVesselsFiltered}
|
||||
onSelectMmsi={setSelectedMmsi}
|
||||
onToggleHighlightMmsi={toggleHighlightedMmsi}
|
||||
onHoverMmsi={(mmsis) => setHoveredMmsiSet(setUniqueSorted(mmsis))}
|
||||
onClearHover={() => setHoveredMmsiSet([])}
|
||||
onHoverPair={(pairMmsis) => setHoveredPairMmsiSet(setUniqueSorted(pairMmsis))}
|
||||
onClearPairHover={() => setHoveredPairMmsiSet([])}
|
||||
onHoverFleet={(ownerKey, fleetMmsis) => {
|
||||
setHoveredFleetOwnerKey(ownerKey);
|
||||
setHoveredFleetMmsiSet(setSortedIfChanged(fleetMmsis));
|
||||
}}
|
||||
onClearFleetHover={() => {
|
||||
setHoveredFleetOwnerKey(null);
|
||||
setHoveredFleetMmsiSet((prev) => (prev.length === 0 ? prev : []));
|
||||
}}
|
||||
hoveredFleetOwnerKey={hoveredFleetOwnerKey}
|
||||
hoveredFleetMmsiSet={hoveredFleetMmsiSet}
|
||||
onContextMenuFleet={handleFleetContextMenu}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -315,7 +385,15 @@ export function DashboardPage() {
|
||||
({legacyVesselsFiltered.length}척)
|
||||
</span>
|
||||
</div>
|
||||
<VesselList vessels={legacyVesselsFiltered} selectedMmsi={selectedMmsi} onSelectMmsi={setSelectedMmsi} />
|
||||
<VesselList
|
||||
vessels={legacyVesselsFiltered}
|
||||
selectedMmsi={selectedMmsi}
|
||||
highlightedMmsiSet={activeHighlightedMmsiSet}
|
||||
onSelectMmsi={setSelectedMmsi}
|
||||
onToggleHighlightMmsi={toggleHighlightedMmsi}
|
||||
onHoverMmsi={(mmsi) => setHoveredMmsiSet([mmsi])}
|
||||
onClearHover={() => setHoveredMmsiSet([])}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="sb" style={{ maxHeight: 130, overflowY: "auto" }}>
|
||||
@ -489,17 +567,32 @@ export function DashboardPage() {
|
||||
targets={targetsForMap}
|
||||
zones={zones}
|
||||
selectedMmsi={selectedMmsi}
|
||||
highlightedMmsiSet={activeHighlightedMmsiSet}
|
||||
hoveredMmsiSet={hoveredMmsiSet}
|
||||
hoveredFleetMmsiSet={hoveredFleetMmsiSet}
|
||||
hoveredPairMmsiSet={hoveredPairMmsiSet}
|
||||
hoveredFleetOwnerKey={hoveredFleetOwnerKey}
|
||||
settings={settings}
|
||||
baseMap={baseMap}
|
||||
projection={projection}
|
||||
overlays={overlays}
|
||||
onSelectMmsi={setSelectedMmsi}
|
||||
onToggleHighlightMmsi={toggleHighlightedMmsi}
|
||||
onViewBboxChange={setViewBbox}
|
||||
legacyHits={legacyHits}
|
||||
pairLinks={pairLinksForMap}
|
||||
fcLinks={fcLinksForMap}
|
||||
fleetCircles={fleetCirclesForMap}
|
||||
fleetFocus={fleetFocus}
|
||||
onProjectionLoadingChange={setIsProjectionLoading}
|
||||
onHoverFleet={(ownerKey, fleetMmsis) => {
|
||||
setHoveredFleetOwnerKey(ownerKey);
|
||||
setHoveredFleetMmsiSet(setSortedIfChanged(fleetMmsis));
|
||||
}}
|
||||
onClearFleetHover={() => {
|
||||
setHoveredFleetOwnerKey(null);
|
||||
setHoveredFleetMmsiSet((prev) => (prev.length === 0 ? prev : []));
|
||||
}}
|
||||
/>
|
||||
<MapLegend />
|
||||
{selectedLegacyVessel ? (
|
||||
|
||||
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
Load Diff
불러오는 중...
Reference in New Issue
Block a user