perf(web): reconcile fleet map incrementally
This commit is contained in:
@@ -7,6 +7,7 @@ import { FleetMap } from './FleetMap';
|
||||
const setData = vi.fn<(data: AMapMassPoint[]) => void>();
|
||||
const setStyle = vi.fn();
|
||||
const addLabels = vi.fn();
|
||||
const removeLabels = vi.fn();
|
||||
const clearLabels = vi.fn();
|
||||
const setLabelsMap = vi.fn();
|
||||
const markerSetMap = vi.fn();
|
||||
@@ -55,6 +56,7 @@ class TestLabelsLayer {
|
||||
labelLayerOptions.push(options);
|
||||
}
|
||||
add = addLabels;
|
||||
remove = removeLabels;
|
||||
clear = clearLabels;
|
||||
setMap = setLabelsMap;
|
||||
}
|
||||
@@ -144,6 +146,7 @@ afterEach(() => {
|
||||
setData.mockReset();
|
||||
setStyle.mockReset();
|
||||
addLabels.mockReset();
|
||||
removeLabels.mockReset();
|
||||
clearLabels.mockReset();
|
||||
setLabelsMap.mockReset();
|
||||
markerSetMap.mockReset();
|
||||
@@ -210,6 +213,41 @@ test('detaches AMap listeners and destroys the map on unmount', async () => {
|
||||
expect(mapDestroy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('skips unchanged refresh redraws and replaces only a moved vehicle label', async () => {
|
||||
window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' };
|
||||
window.AMapLoader = { load: vi.fn(async () => amapMock()) };
|
||||
const view = render(<FleetMap vehicles={[]} monitorMap={pointMap} onSelect={() => undefined} />);
|
||||
await waitFor(() => expect(addLabels).toHaveBeenCalled());
|
||||
const dataCalls = setData.mock.calls.length;
|
||||
const styleCalls = setStyle.mock.calls.length;
|
||||
const addCalls = addLabels.mock.calls.length;
|
||||
const removeCalls = removeLabels.mock.calls.length;
|
||||
const clearCalls = clearLabels.mock.calls.length;
|
||||
|
||||
await act(async () => {
|
||||
view.rerender(<FleetMap vehicles={[]} monitorMap={{ ...pointMap, asOf: '2026-07-14T01:00:15Z' }} onSelect={() => undefined} />);
|
||||
await Promise.resolve();
|
||||
});
|
||||
expect(setData).toHaveBeenCalledTimes(dataCalls);
|
||||
expect(setStyle).toHaveBeenCalledTimes(styleCalls);
|
||||
expect(addLabels).toHaveBeenCalledTimes(addCalls);
|
||||
expect(removeLabels).toHaveBeenCalledTimes(removeCalls);
|
||||
expect(clearLabels).toHaveBeenCalledTimes(clearCalls);
|
||||
|
||||
view.rerender(<FleetMap vehicles={[]} monitorMap={{
|
||||
...pointMap,
|
||||
asOf: '2026-07-14T01:00:30Z',
|
||||
points: [{ ...pointMap.points[0], longitude: 113.27 }, pointMap.points[1]]
|
||||
}} onSelect={() => undefined} />);
|
||||
await waitFor(() => expect(setData).toHaveBeenCalledTimes(dataCalls + 1));
|
||||
expect(setStyle).toHaveBeenCalledTimes(styleCalls);
|
||||
expect(removeLabels).toHaveBeenCalledTimes(removeCalls + 1);
|
||||
expect(addLabels).toHaveBeenCalledTimes(addCalls + 1);
|
||||
const replacementLabels = addLabels.mock.calls[addLabels.mock.calls.length - 1]?.[0] as TestLabelMarker[];
|
||||
expect(replacementLabels).toHaveLength(1);
|
||||
expect((replacementLabels[0].options.text as { content: string }).content).toBe('粤A12345');
|
||||
});
|
||||
|
||||
test('converts AMap GCJ-02 bounds back to WGS-84 before requesting monitor data', async () => {
|
||||
const [west, south] = wgs84ToGcj02(113, 22);
|
||||
const [east, north] = wgs84ToGcj02(114, 24);
|
||||
@@ -334,10 +372,10 @@ test('renders one selected plate and smoothly follows it until the map is dragge
|
||||
expect(toggle).toHaveAttribute('aria-pressed', 'true');
|
||||
fireEvent.click(toggle);
|
||||
await waitFor(() => expect(toggle).toHaveAttribute('aria-pressed', 'false'));
|
||||
expect(clearLabels).toHaveBeenCalled();
|
||||
const selectedOnlyLabels = addLabels.mock.calls[addLabels.mock.calls.length - 1]?.[0] as TestLabelMarker[];
|
||||
expect(selectedOnlyLabels).toHaveLength(1);
|
||||
expect((selectedOnlyLabels[0].options.text as { content: string }).content).toBe('粤B67890');
|
||||
expect(removeLabels).toHaveBeenCalled();
|
||||
const hiddenFloatingLabels = removeLabels.mock.calls[removeLabels.mock.calls.length - 1]?.[0] as TestLabelMarker[];
|
||||
expect(hiddenFloatingLabels).toHaveLength(1);
|
||||
expect((hiddenFloatingLabels[0].options.text as { content: string }).content).toBe('粤A12345');
|
||||
});
|
||||
|
||||
test('renders every nearby plate with staggered positions at maximum zoom', async () => {
|
||||
@@ -369,6 +407,7 @@ test('renders every nearby plate with staggered positions at maximum zoom', asyn
|
||||
view.rerender(<FleetMap vehicles={[]} monitorMap={crowdedMap} selectedVin="LTEST000000000002" onSelect={() => undefined} />);
|
||||
await waitFor(() => expect(addLabels.mock.calls.length).toBeGreaterThan(labelRenderCount));
|
||||
const selectedDenseMarkers = addLabels.mock.calls[addLabels.mock.calls.length - 1]?.[0] as TestLabelMarker[];
|
||||
expect(selectedDenseMarkers).toHaveLength(1);
|
||||
expect(selectedDenseMarkers.every((marker) => marker.options.icon == null)).toBe(true);
|
||||
expect(selectedDenseMarkers.find((marker) => marker.options.rank === 100)).toBeDefined();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user