perf(tracks): defer empty map runtime
This commit is contained in:
@@ -98,6 +98,68 @@ afterEach(() => {
|
|||||||
mapInstances.length = 0;
|
mapInstances.length = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('defers the map runtime until valid track data exists and releases it when data is cleared', async () => {
|
||||||
|
window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' };
|
||||||
|
const load = vi.fn(async () => amapMock());
|
||||||
|
window.AMapLoader = { load };
|
||||||
|
const view = render(<TrackMap
|
||||||
|
points={[]}
|
||||||
|
stops={[]}
|
||||||
|
activeIndex={0}
|
||||||
|
showStops={false}
|
||||||
|
follow
|
||||||
|
onSelectIndex={() => undefined}
|
||||||
|
onFollowChange={() => undefined}
|
||||||
|
/>);
|
||||||
|
|
||||||
|
expect(load).not.toHaveBeenCalled();
|
||||||
|
expect(mapInstances).toHaveLength(0);
|
||||||
|
expect(view.container.querySelector('.v2-map-state')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
view.rerender(<TrackMap
|
||||||
|
points={points}
|
||||||
|
stops={[]}
|
||||||
|
activeIndex={0}
|
||||||
|
showStops={false}
|
||||||
|
follow
|
||||||
|
onSelectIndex={() => undefined}
|
||||||
|
onFollowChange={() => undefined}
|
||||||
|
/>);
|
||||||
|
await waitFor(() => expect(mapInstances).toHaveLength(1));
|
||||||
|
expect(load).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
view.rerender(<TrackMap
|
||||||
|
points={[]}
|
||||||
|
stops={[]}
|
||||||
|
activeIndex={0}
|
||||||
|
showStops={false}
|
||||||
|
follow
|
||||||
|
onSelectIndex={() => undefined}
|
||||||
|
onFollowChange={() => undefined}
|
||||||
|
/>);
|
||||||
|
await waitFor(() => expect(mapDestroy).toHaveBeenCalledTimes(1));
|
||||||
|
expect(mapInstances).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('does not initialize the map for rows without a valid coordinate', () => {
|
||||||
|
window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' };
|
||||||
|
const load = vi.fn(async () => amapMock());
|
||||||
|
window.AMapLoader = { load };
|
||||||
|
render(<TrackMap
|
||||||
|
points={[{ ...points[0], longitude: 0, latitude: 0 }]}
|
||||||
|
stops={[]}
|
||||||
|
activeIndex={0}
|
||||||
|
showStops={false}
|
||||||
|
follow
|
||||||
|
onSelectIndex={() => undefined}
|
||||||
|
onFollowChange={() => undefined}
|
||||||
|
/>);
|
||||||
|
|
||||||
|
expect(load).not.toHaveBeenCalled();
|
||||||
|
expect(mapInstances).toHaveLength(0);
|
||||||
|
expect(document.body).toHaveTextContent('当前轨迹没有可展示的有效坐标');
|
||||||
|
});
|
||||||
|
|
||||||
test('uses the playback cadence for follow animation and advances the passed path', async () => {
|
test('uses the playback cadence for follow animation and advances the passed path', async () => {
|
||||||
window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' };
|
window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' };
|
||||||
window.AMapLoader = { load: vi.fn(async () => amapMock()) };
|
window.AMapLoader = { load: vi.fn(async () => amapMock()) };
|
||||||
|
|||||||
@@ -28,8 +28,9 @@ export function TrackMap({ points, stops, activeIndex, showStops, follow, follow
|
|||||||
const pathRef = useRef<[number, number][]>([]);
|
const pathRef = useRef<[number, number][]>([]);
|
||||||
const selectRef = useRef(onSelectIndex);
|
const selectRef = useRef(onSelectIndex);
|
||||||
const followChangeRef = useRef(onFollowChange);
|
const followChangeRef = useRef(onFollowChange);
|
||||||
const [state, setState] = useState<'loading' | 'ready' | 'fallback' | 'error'>('loading');
|
|
||||||
const valid = useMemo(() => points.map((point, index) => ({ point, index })).filter(({ point }) => isValidAMapCoordinate(point.longitude, point.latitude)), [points]);
|
const valid = useMemo(() => points.map((point, index) => ({ point, index })).filter(({ point }) => isValidAMapCoordinate(point.longitude, point.latitude)), [points]);
|
||||||
|
const hasValidPoints = valid.length > 0;
|
||||||
|
const [state, setState] = useState<'idle' | 'loading' | 'ready' | 'fallback' | 'error'>(() => hasValidPoints ? 'loading' : 'idle');
|
||||||
const passedCountByPoint = useMemo(() => {
|
const passedCountByPoint = useMemo(() => {
|
||||||
const counts = new Uint16Array(points.length);
|
const counts = new Uint16Array(points.length);
|
||||||
let validIndex = 0;
|
let validIndex = 0;
|
||||||
@@ -44,6 +45,8 @@ export function TrackMap({ points, stops, activeIndex, showStops, follow, follow
|
|||||||
useEffect(() => { followChangeRef.current = onFollowChange; }, [onFollowChange]);
|
useEffect(() => { followChangeRef.current = onFollowChange; }, [onFollowChange]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!hasValidPoints) { setState('idle'); return; }
|
||||||
|
setState('loading');
|
||||||
if (!containerRef.current || !isAMapConfigured(getAMapConfig())) { setState('fallback'); return; }
|
if (!containerRef.current || !isAMapConfigured(getAMapConfig())) { setState('fallback'); return; }
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
let mapInstance: AMapMap | undefined;
|
let mapInstance: AMapMap | undefined;
|
||||||
@@ -81,7 +84,7 @@ export function TrackMap({ points, stops, activeIndex, showStops, follow, follow
|
|||||||
mapRef.current = null;
|
mapRef.current = null;
|
||||||
amapRef.current = null;
|
amapRef.current = null;
|
||||||
};
|
};
|
||||||
}, []);
|
}, [hasValidPoints]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const AMap = amapRef.current;
|
const AMap = amapRef.current;
|
||||||
@@ -144,8 +147,9 @@ export function TrackMap({ points, stops, activeIndex, showStops, follow, follow
|
|||||||
|
|
||||||
return <div className="v2-track-map">
|
return <div className="v2-track-map">
|
||||||
<div ref={containerRef} className="v2-track-map-canvas" aria-label="历史轨迹地图" />
|
<div ref={containerRef} className="v2-track-map-canvas" aria-label="历史轨迹地图" />
|
||||||
{state !== 'ready' ? <div className={`v2-map-state is-${state}`}>
|
{state !== 'ready' && (state !== 'idle' || points.length > 0) ? <div className={`v2-map-state is-${state}`}>
|
||||||
{state === 'loading' ? <><span className="v2-spinner" />轨迹地图加载中</> : null}
|
{state === 'loading' ? <><span className="v2-spinner" />轨迹地图加载中</> : null}
|
||||||
|
{state === 'idle' ? '当前轨迹没有可展示的有效坐标' : null}
|
||||||
{state === 'fallback' ? `地图未配置,已载入 ${valid.length} 个有效轨迹点` : null}
|
{state === 'fallback' ? `地图未配置,已载入 ${valid.length} 个有效轨迹点` : null}
|
||||||
{state === 'error' ? '地图加载失败,请检查高德地图配置' : null}
|
{state === 'error' ? '地图加载失败,请检查高德地图配置' : null}
|
||||||
</div> : null}
|
</div> : null}
|
||||||
|
|||||||
Reference in New Issue
Block a user