네이티브 맵 최적화 반응
지도에 사용되는 라이브러리:
https://www.npmjs.com/package/react-native-maps
이 게시물은 막대한 양의 마커/폴리곤이 지도에 표시될 때 앱 충돌을 방지하고 최적화하는 방법에 관한 것입니다. 여러 데이터가 있는 지도를 사용할 때 많은 성능 문제가 있으며 확대/축소 수준에 따라 사용자 지정 마커를 업데이트해야 합니다. 따라서 두 플랫폼 모두에서 앱을 쉽게 실행하는 데 필요한 각 단계를 안내해 드리겠습니다.
사용 중인 샘플 데이터:
export const kmlData = {
status: true,
data: [
{
id: 3,
polygons: [
{latitude: 24.79672061085053, longitude: 46.69632228737188},
{latitude: 24.79730088563427, longitude: 46.6960244924467},
{latitude: 24.7969867813524, longitude: 46.69528762847696},
{latitude: 24.796409228271, longitude: 46.69558319234557},
{latitude: 24.79672061085053, longitude: 46.69632228737188},
],
center: {latitude: 24.796853402304418, longitude: 46.69580273788693},
},
{
id: 5,
polygons: [
{latitude: 24.79478092109267, longitude: 46.69287860779153},
{latitude: 24.79491840277788, longitude: 46.69320194403617},
{latitude: 24.79511421069013, longitude: 46.6931029170428},
{latitude: 24.79497672880431, longitude: 46.69277958136081},
{latitude: 24.79478092109267, longitude: 46.69287860779153},
],
center: {latitude: 24.794971095661616, longitude: 46.693035073221495},
},
*
*
*
*
]}
설명:
trackViewChanges
의 Map
prop은 주로 Android에서 충돌/지연 없이 맵을 실행하려는 경우 항상 false로 유지되어야 합니다. 활성화하면 마커가 첫 번째 렌더링 통과 후 정보 창의 내용을 변경할 수 있지만 성능이 저하되므로 필요하지 않을 때마다 비활성화하는 것이 좋습니다. trackViewChanges
를 true로 설정하고 약간의 지연 후 다시 false로 설정합니다. 하지만 이 수정으로 Android가 제대로 작동하지 않습니다. key
속성을 제공하고 항상 trackViewChanges
를 false로 설정합니다. 추가 사항:
getCenterOfAllPolygon()
는 지도의 폴리곤 내부에 어떤 뷰도 넣을 수 없고 그 위에 마커를 사용해야 하는 폴리곤 위에 뷰를 표시할 수 없기 때문에 폴리곤 중앙에 마커를 배치할 수 있도록 폴리곤의 중심을 제공합니다. animateToRegion(coordinate,delay)
는 특정 지역으로 이동하는 데 사용됩니다. fitToCoordinates(polygonsArray, {edgePadding,animated})
는 다각형을 클릭하여 측면을 자르지 않고 다각형 수준으로 확대하려는 경우에 사용됩니다. 파일
Map.js
export default function MapPlots({}) {
const mapRef = useRef(null);
const markerRef = useRef(null);
const [markerType, setMarkerType] = useState(0);
const [clickedPolygon, setClickedPolygon] = useState();
const [mapType, setmapType] = useState(SATELLITE_MAP_MODE);
const [trackViewChanges, settrackViewChanges] = useState(false);
const [regionChanged, setregionChanged] = useState(null);
const {data} = kmlData;
const isIOS = Platform.OS === 'ios' ? true : false;
const coordinatesData = data.map((v, i) => ({
...v,
color:
i % 2 === 0
? [COLOR_GREEN_OPACITY, COLOR_GREEN]
: [COLOR_RED_OPACITY, COLOR_RED],
}));
const navigation = useNavigation();
const initialRegion = {
...coordinatesData[0]?.polygons[0],
latitudeDelta: 1,
longitudeDelta: 50,
};
console.log('coordinatesDatacoordinatesData', coordinatesData);
const onMapReady = () => {
InteractionManager.runAfterInteractions(() => goToLocation());
// getCenterOfAllPolygon();
};
const goToLocation = () => {
let initCoordinates = coordinatesData[0]?.polygons[0] || [];
let c2 = {
...initCoordinates,
latitudeDelta: 0.005,
longitudeDelta: 0.005,
};
mapRef?.current?.animateToRegion(c2, 5 * 1000);
};
// const getCenterOfAllPolygon = () => {
// let centers = [];
// polygonsCoordinates.map((v, i) => {
// let c = getCenterPolygon(v);
// centers.push(c);
// });
// setPolygonCenters(centers);
// console.log('centers', centers);
// };
// let getCenterPolygon = coordinates => {
// let x = coordinates.map(c => c.latitude);
// let y = coordinates.map(c => c.longitude);
// let minX = Math.min.apply(null, x);
// let maxX = Math.max.apply(null, x);
// let minY = Math.min.apply(null, y);
// let maxY = Math.max.apply(null, y);
// return {
// latitude: (minX + maxX) / 2,
// longitude: (minY + maxY) / 2,
// };
// };
const onPressPolygon = (polygons, index = 0) => {
console.log('onPressPolygononPressPolygon', polygons, index);
setClickedPolygon(index);
mapRef?.current?.fitToCoordinates(polygons, {
edgePadding: {top: 2, right: 2, bottom: 2, left: 2},
animated: true,
});
};
const onRegionChangeComplete = param => {
console.log('onRegionChangeComplete0', param);
if (parseInt(param?.latitudeDelta.toFixed(2)) < 0.03) {
//50//1
if (param?.latitudeDelta.toFixed(5) !== regionChanged?.latitudeDelta) {
setregionChanged({
...param,
latitudeDelta: param?.latitudeDelta.toFixed(5),
longitudeDelta: param?.longitudeDelta.toFixed(5),
});
let toFixedLat = param?.latitudeDelta;
console.log('onRegionChangeComplete1', param);
if (toFixedLat > 0.005) {
setMarkerType(1);
} else if (toFixedLat < 0.005) {
setMarkerType(2);
}
//region change 0=nothing show
//region change 1=dot show
//region change 2=marker show
settrackViewChanges(true);
setTimeout(() => {
markerRef?.current?.redraw();
settrackViewChanges(false);
}, 100);
}
}
};
const setMapTypeFunc = () => {
setmapType(v =>
v === STANDARD_MAP_MODE ? SATELLITE_MAP_MODE : STANDARD_MAP_MODE,
);
};
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.mapType(mapType)}
onPress={setMapTypeFunc}>
<CustomIcon
color={
mapType === STANDARD_MAP_MODE ? COLOR_GRAY_70 : COLOR_SECONDARY
}
name={ICONOGRAPHY.FLOORS}
size={20}
/>
</TouchableOpacity>
{markerType ? null : (
<View
style={{
...styles.map,
...styles.loader,
}}>
<ActivityIndicator color={COLOR_PRIMARY} size="large" />
</View>
)}
<MapView
provider={MapView.PROVIDER_GOOGLE}
ref={mapRef}
style={styles.map}
onMapReady={onMapReady}
initialRegion={initialRegion}
mapType={mapType}
loadingEnabled={true}
showsCompass={true}
onRegionChangeComplete={onRegionChangeComplete}>
{!markerType
? null
: coordinatesData.map((item, index) => (
<View key={index}>
<Polygon
coordinates={item?.polygons}
strokeColor={
index !== clickedPolygon ? COLOR_PLOT_BORDER : COLOR_BLACK
} // fallback for when `strokeColors` is not supported by the map-provider
fillColor={item?.color[index !== clickedPolygon ? 0 : 1]}
strokeWidth={index !== clickedPolygon ? 0.3 : 2}
tappable
geodesic
onPress={() => onPressPolygon(item?.polygons, index)}
/>
<Marker
ref={markerRef}
key={
isIOS() ? index : `${index}${trackViewChanges}`
// isIOS() ? index : `${index}${trackViewChanges}${Date.now()}`
}
opacity={markerType ? 1 : 0}
anchor={{x: 0.5, y: 0.5}}
centerOffset={{x: 0.5, y: 0.5}}
onPress={() => onPressPolygon(item?.polygons, index)}
coordinate={item?.center}
tracksViewChanges={isIOS() ? trackViewChanges : false}>
{!markerType ? (
<View />
) : markerType === 1 ? (
<View style={styles.dot} />
) : (
<Text style={styles.markerText}>1001</Text>
)}
</Marker>
</View>
))}
</MapView>
{clickedPolygon === null || clickedPolygon === undefined ? null : (
<PopupBottom
navigation={navigation}
clickedPolygon={clickedPolygon}
onPressCloseButton={() => setClickedPolygon(null)}
/>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
},
back: {
height: 20,
width: 20,
backgroundColor: 'red',
position: 'absolute',
zIndex: 1,
left: 20,
top: 50,
},
map: {
...StyleSheet.absoluteFillObject,
},
markerText: {color: '#000', fontSize: 12},
mapType: mapType => ({
position: 'absolute',
zIndex: 1,
top: 160,
left: 16,
height: 30,
width: 30,
borderRadius: 4,
backgroundColor: COLOR_WHITE,
borderWidth: 1,
borderColor: mapType === STANDARD_MAP_MODE ? COLOR_WHITE : COLOR_SECONDARY,
justifyContent: 'center',
alignItems: 'center',
...shadow.shadow,
}),
loader: {
justifyContent: 'center',
alignItems: 'center',
zIndex: 100,
},
dot: {
height: 10,
width: 10,
borderRadius: 10,
backgroundColor: COLOR_WHITE,
},
});
Reference
이 문제에 관하여(네이티브 맵 최적화 반응), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ajmal_hasan/react-native-map-optimisation-59na텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)