perf(monitor): isolate follow viewport events
This commit is contained in:
@@ -14,7 +14,7 @@ const markerSetMap = vi.fn();
|
||||
const markerSetPosition = vi.fn();
|
||||
const labelSetPosition = vi.fn();
|
||||
const setZoomAndCenter = vi.fn();
|
||||
const setCenter = vi.fn();
|
||||
const setCenter = vi.fn(() => mapHandlers.get('moveend')?.({}));
|
||||
const panTo = vi.fn();
|
||||
const mapOff = vi.fn();
|
||||
const mapDestroy = vi.fn();
|
||||
@@ -521,6 +521,24 @@ test('renders one selected plate and smoothly follows it until the map is dragge
|
||||
expect((hiddenFloatingLabels[0].options.text as { content: string }).content).toBe('粤A12345');
|
||||
});
|
||||
|
||||
test('does not treat intermediate programmatic follow frames as user viewport changes', async () => {
|
||||
useFastAnimationFrames();
|
||||
window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' };
|
||||
window.AMapLoader = { load: vi.fn(async () => amapMock()) };
|
||||
const onViewportChange = vi.fn();
|
||||
const view = render(<FleetMap vehicles={[]} monitorMap={pointMap} selectedVin="LTEST000000000001" onSelect={() => undefined} onViewportChange={onViewportChange} />);
|
||||
await waitFor(() => expect(onViewportChange).toHaveBeenCalled());
|
||||
onViewportChange.mockReset();
|
||||
|
||||
view.rerender(<FleetMap vehicles={[]} monitorMap={{
|
||||
...pointMap,
|
||||
points: [{ ...pointMap.points[0], longitude: 113.27, latitude: 23.14 }, pointMap.points[1]]
|
||||
}} selectedVin="LTEST000000000001" onSelect={() => undefined} onViewportChange={onViewportChange} />);
|
||||
|
||||
await waitFor(() => expect(setCenter).toHaveBeenLastCalledWith(wgs84ToGcj02(113.27, 23.14)), { timeout: 1_800 });
|
||||
await waitFor(() => expect(onViewportChange).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
|
||||
test('renders every nearby plate with staggered positions at maximum zoom', async () => {
|
||||
getZoom.mockReturnValue(20);
|
||||
window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' };
|
||||
|
||||
@@ -302,6 +302,7 @@ export function FleetMap({ vehicles, selectedVin, onSelect, monitorMap, onSelect
|
||||
const selectionPositionRef = useRef('');
|
||||
const centeredVinRef = useRef('');
|
||||
const followSelectedRef = useRef(true);
|
||||
const programmaticFollowRef = useRef(false);
|
||||
const selectedVinRef = useRef(selectedVin);
|
||||
const [state, setState] = useState<'loading' | 'ready' | 'fallback' | 'error'>('loading');
|
||||
const [loadAttempt, setLoadAttempt] = useState(0);
|
||||
@@ -389,6 +390,7 @@ export function FleetMap({ vehicles, selectedVin, onSelect, monitorMap, onSelect
|
||||
const denseLabels = AMap.LabelsLayer ? new AMap.LabelsLayer({ zooms: [19, 20], zIndex: 110, collision: false, allowCollision: true }) : null;
|
||||
labels?.setMap(map);
|
||||
notifyViewport = () => {
|
||||
if (programmaticFollowRef.current) return;
|
||||
setMapZoom(map.getZoom?.() ?? 5);
|
||||
window.clearTimeout(viewportTimerRef.current);
|
||||
viewportTimerRef.current = window.setTimeout(() => {
|
||||
@@ -400,6 +402,7 @@ export function FleetMap({ vehicles, selectedVin, onSelect, monitorMap, onSelect
|
||||
map.on?.('zoomend', notifyViewport);
|
||||
stopFollowing = () => {
|
||||
if (!centeredVinRef.current) return;
|
||||
programmaticFollowRef.current = false;
|
||||
followSelectedRef.current = false;
|
||||
setFollowSelected(false);
|
||||
};
|
||||
@@ -431,6 +434,7 @@ export function FleetMap({ vehicles, selectedVin, onSelect, monitorMap, onSelect
|
||||
pointAnimationFrameRef.current = undefined;
|
||||
pointAnimationTimerRef.current = undefined;
|
||||
movingPointIDsRef.current.clear();
|
||||
programmaticFollowRef.current = false;
|
||||
if (selectMassPoint) massInstance?.off?.('click', selectMassPoint);
|
||||
if (notifyViewport) {
|
||||
mapInstance?.off?.('moveend', notifyViewport);
|
||||
@@ -493,6 +497,7 @@ export function FleetMap({ vehicles, selectedVin, onSelect, monitorMap, onSelect
|
||||
window.clearTimeout(pointAnimationTimerRef.current);
|
||||
pointAnimationFrameRef.current = undefined;
|
||||
pointAnimationTimerRef.current = undefined;
|
||||
programmaticFollowRef.current = false;
|
||||
const previousData = renderedMassDataRef.current;
|
||||
const previousDataByID = new Map(previousData.map((point) => [point.id, point]));
|
||||
const vehiclePointIDs = new Set(monitorMode ? mapPoints.map((point) => point.vin) : fallbackPoints.map((point) => point.vin));
|
||||
@@ -531,6 +536,7 @@ export function FleetMap({ vehicles, selectedVin, onSelect, monitorMap, onSelect
|
||||
selectionRef.current?.setPosition?.(motion.point.lnglat);
|
||||
const motionComplete = elapsed >= motion.durationMs;
|
||||
if (followSelectedRef.current && !selectedFollowComplete && (elapsed - lastFollowAt >= MAP_FOLLOW_FRAME_MS || motionComplete)) {
|
||||
programmaticFollowRef.current = !motionComplete;
|
||||
mapRef.current?.setCenter?.(motion.point.lnglat);
|
||||
lastFollowAt = elapsed;
|
||||
selectedFollowComplete = motionComplete;
|
||||
|
||||
Reference in New Issue
Block a user