perf: improve display of visitor map if data is too much

This commit is contained in:
moonrailgun 2024-10-04 21:19:20 +08:00
parent 9d559b93d1
commit 9bc8c63fe2
2 changed files with 35 additions and 5 deletions

View File

@ -5,7 +5,7 @@ import {
PointLayer, PointLayer,
PointLayerProps, PointLayerProps,
} from '@antv/larkmap'; } from '@antv/larkmap';
import React from 'react'; import React, { useMemo } from 'react';
import { AppRouterOutput } from '../../../api/trpc'; import { AppRouterOutput } from '../../../api/trpc';
import { useGlobalConfig } from '../../../hooks/useConfig'; import { useGlobalConfig } from '../../../hooks/useConfig';
import { useSettingsStore } from '../../../store/settings'; import { useSettingsStore } from '../../../store/settings';
@ -76,10 +76,18 @@ export const VisitorLarkMap: React.FC<{
parser: { type: 'json', x: 'longitude', y: 'latitude' }, parser: { type: 'json', x: 'longitude', y: 'latitude' },
}; };
const size = useMemo(() => {
if (props.data.length > 5000) {
return 3;
}
return 5;
}, [props.data.length]);
return ( return (
<LarkMap {...config} style={{ height: '60vh' }}> <LarkMap {...config} style={{ height: '60vh' }}>
<FullscreenControl /> <FullscreenControl />
<PointLayer {...layerOptions} source={source} /> <PointLayer {...layerOptions} size={size} source={source} />
</LarkMap> </LarkMap>
); );
}); });

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useMemo } from 'react';
import { AppRouterOutput } from '../../../api/trpc'; import { AppRouterOutput } from '../../../api/trpc';
import { MapContainer, CircleMarker, Popup, TileLayer } from 'react-leaflet'; import { MapContainer, CircleMarker, Popup, TileLayer } from 'react-leaflet';
import { mapCenter } from './utils'; import { mapCenter } from './utils';
@ -7,11 +7,13 @@ import './VisitorLeafletMap.css';
import { useTranslation } from '@i18next-toolkit/react'; import { useTranslation } from '@i18next-toolkit/react';
export const UserDataPoint: React.FC<{ export const UserDataPoint: React.FC<{
pointRadius?: number;
longitude: number; longitude: number;
latitude: number; latitude: number;
count: number; count: number;
}> = React.memo((props) => { }> = React.memo((props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const pointRadius = props.pointRadius ?? 5;
return ( return (
<CircleMarker <CircleMarker
@ -19,7 +21,7 @@ export const UserDataPoint: React.FC<{
lat: props.latitude, lat: props.latitude,
lng: props.longitude, lng: props.longitude,
}} }}
radius={5} radius={pointRadius}
stroke={false} stroke={false}
fill={true} fill={true}
fillColor="rgb(236,112,20)" fillColor="rgb(236,112,20)"
@ -38,6 +40,22 @@ UserDataPoint.displayName = 'UserDataPoint';
export const VisitorLeafletMap: React.FC<{ export const VisitorLeafletMap: React.FC<{
data: AppRouterOutput['website']['geoStats']; data: AppRouterOutput['website']['geoStats'];
}> = React.memo((props) => { }> = React.memo((props) => {
const pointRadius = useMemo(() => {
if (props.data.length > 20000) {
return 1;
}
if (props.data.length > 5000) {
return 2;
}
if (props.data.length > 1000) {
return 3;
}
return 5;
}, [props.data.length]);
return ( return (
<MapContainer <MapContainer
className="h-[60vh] w-full" className="h-[60vh] w-full"
@ -50,7 +68,11 @@ export const VisitorLeafletMap: React.FC<{
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
{props.data.map((item) => ( {props.data.map((item) => (
<UserDataPoint key={`${item.longitude},${item.latitude}`} {...item} /> <UserDataPoint
key={`${item.longitude},${item.latitude}`}
pointRadius={pointRadius}
{...item}
/>
))} ))}
</MapContainer> </MapContainer>
); );