@mj-studio/react-native-naver-map
Version:
Naver Map Component for React Native
436 lines (432 loc) • 13.3 kB
JavaScript
;
import hash from 'object-hash';
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
import { cameraChangeReasonFromNumber, cameraEasingToNumber, convertJsImagePropToNativeProp, createCameraInstance } from "../internal/Util.js";
import { Const } from "../internal/util/Const.js";
import { useStableCallback } from "../internal/util/useStableCallback.js";
import { Commands, default as NativeNaverMapView } from '../spec/RNCNaverMapViewNativeComponent';
/**
* @category Hell
*/
import { jsx as _jsx } from "react/jsx-runtime";
function clamp(v, min, max) {
return Math.min(max, Math.max(min, v));
}
const southKoreaExtent = {
latitude: 31.43,
longitude: 122.37,
latitudeDelta: 44.35 - 31.43,
longitudeDelta: 132 - 122.37
};
const nullRegion = {
latitude: Const.NULL_NUMBER,
longitude: Const.NULL_NUMBER,
latitudeDelta: Const.NULL_NUMBER,
longitudeDelta: Const.NULL_NUMBER
};
const nullCamera = {
latitude: Const.NULL_NUMBER,
longitude: Const.NULL_NUMBER,
zoom: Const.NULL_NUMBER,
tilt: Const.NULL_NUMBER,
bearing: Const.NULL_NUMBER
};
export const NaverMapView = /*#__PURE__*/forwardRef(({
camera,
initialCamera,
region,
initialRegion,
animationDuration = 0,
animationEasing = Const.DEFAULT_EASING,
mapType = 'Basic',
layerGroups = {
BUILDING: true,
BICYCLE: false,
CADASTRAL: false,
MOUNTAIN: false,
TRAFFIC: false,
TRANSIT: false
},
isIndoorEnabled = false,
isNightModeEnabled = false,
isLiteModeEnabled = false,
lightness = 0,
buildingHeight = 1,
symbolScale = 1,
symbolPerspectiveRatio = 1,
mapPadding,
isShowCompass = true,
isShowIndoorLevelPicker = true,
isShowLocationButton = true,
isShowScaleBar = true,
isShowZoomControls = true,
minZoom,
maxZoom,
extent,
isExtentBoundedInKorea,
logoAlign,
logoMargin,
onCameraChanged: onCameraChangedProp,
onCameraIdle: onCameraIdleProp,
onTapMap: onTapMapProp,
onInitialized,
onOptionChanged,
isScrollGesturesEnabled = true,
isZoomGesturesEnabled = true,
isTiltGesturesEnabled = true,
isRotateGesturesEnabled = true,
isStopGesturesEnabled = true,
isUseTextureViewAndroid = false,
locale,
clusters,
fpsLimit = 0,
// locationOverlay,
onTapClusterLeaf,
...rest
}, ref) => {
const innerRef = useRef(null);
const isLeafTapCallbackExist = !!onTapClusterLeaf;
const _clusters = useMemo(() => {
if (!clusters || clusters.length === 0) {
return {
key: '',
clusters: [],
isLeafTapCallbackExist
};
}
let propKey = '';
const ret = [];
for (const {
animate = true,
markers,
// eslint-disable-next-line @typescript-eslint/no-shadow
minZoom = Const.MIN_ZOOM,
// eslint-disable-next-line @typescript-eslint/no-shadow
maxZoom = Const.MAX_ZOOM,
screenDistance = Const.DEFAULT_SCREEN_DISTANCE,
width,
height
} of clusters) {
const key = hash([animate, maxZoom, minZoom, screenDistance, markers, width, height]);
ret.push({
key,
animate,
markers: markers.map(m => ({
...m,
image: convertJsImagePropToNativeProp(m.image ?? {
symbol: 'green'
})
})),
maxZoom,
minZoom,
screenDistance,
width,
height
});
propKey += `${key}---`;
}
return {
key: hash(propKey),
clusters: ret,
isLeafTapCallbackExist
};
}, [clusters, isLeafTapCallbackExist]);
// const _locationOverlay: NativeLocationOverlayProp | undefined =
// useMemo(() => {
// if (!locationOverlay)
// return Platform.OS === 'ios'
// ? { circleOutlineWidth: Const.NULL_NUMBER }
// : undefined;
// return {
// isVisible: locationOverlay.isVisible,
// position: locationOverlay.position,
// bearing: locationOverlay.bearing,
// image: locationOverlay.image
// ? convertJsImagePropToNativeProp(locationOverlay.image)
// : undefined,
// imageWidth: locationOverlay.imageWidth,
// imageHeight: locationOverlay.imageHeight,
// anchor: locationOverlay.anchor,
// subImage: locationOverlay.subImage
// ? convertJsImagePropToNativeProp(locationOverlay.subImage)
// : undefined,
// subImageWidth: locationOverlay.subImageWidth,
// subImageHeight: locationOverlay.subImageHeight,
// subAnchor: locationOverlay.subAnchor,
// circleRadius: locationOverlay.circleRadius,
// circleColor: locationOverlay.circleColor
// ? (processColor(locationOverlay.circleColor) as number)
// : undefined,
// circleOutlineWidth: locationOverlay.circleOutlineWidth,
// circleOutlineColor: locationOverlay.circleOutlineColor
// ? (processColor(locationOverlay.circleOutlineColor) as number)
// : undefined,
// } satisfies NativeLocationOverlayProp;
// }, [locationOverlay]);
const onCameraChanged = useStableCallback(({
nativeEvent: {
bearing,
latitude,
longitude,
reason,
tilt,
zoom,
regionLatitude,
regionLatitudeDelta,
regionLongitude,
regionLongitudeDelta
}
}) => {
onCameraChangedProp?.({
zoom,
tilt,
reason: cameraChangeReasonFromNumber(reason),
latitude,
longitude,
bearing,
region: {
latitude: regionLatitude,
longitude: regionLongitude,
latitudeDelta: regionLatitudeDelta,
longitudeDelta: regionLongitudeDelta
}
});
});
const onCameraIdle = useStableCallback(({
nativeEvent: {
bearing,
latitude,
longitude,
tilt,
zoom,
regionLatitude,
regionLatitudeDelta,
regionLongitude,
regionLongitudeDelta
}
}) => {
onCameraIdleProp?.({
zoom,
tilt,
latitude,
longitude,
bearing,
region: {
latitude: regionLatitude,
longitude: regionLongitude,
latitudeDelta: regionLatitudeDelta,
longitudeDelta: regionLongitudeDelta
}
});
});
const onTapMap = useStableCallback(({
nativeEvent: {
longitude,
latitude,
x,
y
}
}) => {
onTapMapProp?.({
longitude,
latitude,
x,
y
});
});
const screenToCoordinatePromise = useRef(undefined);
const coordinateToScreenPromise = useRef(undefined);
useEffect(() => {
return () => {
screenToCoordinatePromise.current?.resolve({
isValid: false,
latitude: 0,
longitude: 0
});
screenToCoordinatePromise.current = undefined;
coordinateToScreenPromise.current?.resolve({
isValid: false,
screenX: 0,
screenY: 0
});
coordinateToScreenPromise.current = undefined;
};
}, []);
const onScreenToCoordinate = useStableCallback(({
nativeEvent
}) => {
screenToCoordinatePromise.current?.resolve(nativeEvent);
screenToCoordinatePromise.current = undefined;
});
const onCoordinateToScreen = useStableCallback(({
nativeEvent
}) => {
coordinateToScreenPromise.current?.resolve(nativeEvent);
coordinateToScreenPromise.current = undefined;
});
useImperativeHandle(ref, () => ({
animateCameraTo: ({
duration,
easing,
latitude,
longitude,
pivot,
zoom = Const.NULL_NUMBER
}) => {
if (innerRef.current) {
Commands.animateCameraTo(innerRef.current, latitude, longitude, duration ?? Const.DEFAULT_ANIM_DURATION, cameraEasingToNumber(easing ?? Const.DEFAULT_EASING), pivot?.x ?? 0.5, pivot?.y ?? 0.5, zoom);
}
},
animateCameraBy: ({
duration,
easing,
x,
y,
pivot
}) => {
if (innerRef.current) {
Commands.animateCameraBy(innerRef.current, x, y, duration ?? Const.DEFAULT_ANIM_DURATION, cameraEasingToNumber(easing ?? Const.DEFAULT_EASING), pivot?.x ?? 0.5, pivot?.y ?? 0.5);
}
},
animateRegionTo: ({
easing,
longitude,
latitude,
duration,
latitudeDelta,
longitudeDelta,
pivot
}) => {
if (innerRef.current) {
Commands.animateRegionTo(innerRef.current, latitude, longitude, latitudeDelta, longitudeDelta, duration ?? Const.DEFAULT_ANIM_DURATION, cameraEasingToNumber(easing ?? Const.DEFAULT_EASING), pivot?.x ?? 0.5, pivot?.y ?? 0.5);
}
},
animateCameraWithTwoCoords: ({
duration,
easing,
coord1,
coord2,
pivot
}) => {
if (innerRef.current) {
const latitude = Math.min(coord1.latitude, coord2.latitude);
const longitude = Math.min(coord1.longitude, coord2.longitude);
const latitudeDelta = Math.abs(coord1.latitude - coord2.latitude);
const longitudeDelta = Math.abs(coord1.longitude - coord2.longitude);
Commands.animateRegionTo(innerRef.current, latitude, longitude, latitudeDelta, longitudeDelta, duration ?? Const.DEFAULT_ANIM_DURATION, cameraEasingToNumber(easing ?? Const.DEFAULT_EASING), pivot?.x ?? 0.5, pivot?.y ?? 0.5);
}
},
cancelAnimation: () => {
if (innerRef.current) {
Commands.cancelAnimation(innerRef.current);
}
},
setLocationTrackingMode: mode => {
if (innerRef.current) {
Commands.setLocationTrackingMode(innerRef.current, mode);
}
},
screenToCoordinate: ({
screenX,
screenY
}) => {
screenToCoordinatePromise.current?.resolve({
isValid: false,
latitude: 0,
longitude: 0
});
screenToCoordinatePromise.current = undefined;
if (innerRef.current) {
const newPromise = new Promise((resolve, reject) => {
screenToCoordinatePromise.current = {
resolve,
reject
};
});
Commands.screenToCoordinate(innerRef.current, screenX, screenY);
return newPromise;
} else {
return new Promise((_, reject) => reject(new Error('ref not set yet')));
}
},
coordinateToScreen: ({
latitude,
longitude
}) => {
coordinateToScreenPromise.current?.resolve({
isValid: false,
screenX: 0,
screenY: 0
});
coordinateToScreenPromise.current = undefined;
if (innerRef.current) {
const newPromise = new Promise((resolve, reject) => {
coordinateToScreenPromise.current = {
resolve,
reject
};
});
Commands.coordinateToScreen(innerRef.current, latitude, longitude);
return newPromise;
} else {
return new Promise((_, reject) => reject(new Error('ref not set yet')));
}
}
}), []);
return /*#__PURE__*/_jsx(NativeNaverMapView, {
ref: innerRef,
mapType: mapType,
layerGroups: (layerGroups?.BUILDING ? 1 : 0) + (layerGroups?.TRAFFIC ? 2 : 0) + (layerGroups?.TRANSIT ? 4 : 0) + (layerGroups?.BICYCLE ? 8 : 0) + (layerGroups?.MOUNTAIN ? 16 : 0) + (layerGroups?.CADASTRAL ? 32 : 0),
camera: camera ? createCameraInstance(camera) : undefined,
initialCamera: !camera && initialCamera ? createCameraInstance(initialCamera) : nullCamera,
region: !camera && !initialCamera ? region : undefined,
initialRegion: !region && !camera && !initialCamera && initialRegion ? initialRegion : nullRegion,
animationDuration: animationDuration,
animationEasing: cameraEasingToNumber(animationEasing),
isIndoorEnabled: isIndoorEnabled,
isNightModeEnabled: isNightModeEnabled,
isLiteModeEnabled: isLiteModeEnabled,
lightness: clamp(lightness, -1, 1),
buildingHeight: clamp(buildingHeight, 0, 1),
symbolScale: clamp(symbolScale, 0, 2),
symbolPerspectiveRatio: clamp(symbolPerspectiveRatio, 0, 1),
onInitialized: onInitialized,
onCameraChanged: onCameraChangedProp ? onCameraChanged : undefined,
onCameraIdle: onCameraIdleProp ? onCameraIdle : undefined,
onTapMap: onTapMapProp ? onTapMap : undefined,
onOptionChanged: onOptionChanged,
mapPadding: mapPadding,
isShowCompass: isShowCompass,
isShowIndoorLevelPicker: isShowIndoorLevelPicker,
isShowLocationButton: isShowLocationButton,
isShowScaleBar: isShowScaleBar,
isShowZoomControls: isShowZoomControls,
minZoom: minZoom,
maxZoom: maxZoom,
extent: extent ? extent : isExtentBoundedInKorea ? southKoreaExtent : undefined,
logoAlign: logoAlign,
logoMargin: logoMargin,
isScrollGesturesEnabled: isScrollGesturesEnabled,
isZoomGesturesEnabled: isZoomGesturesEnabled,
isTiltGesturesEnabled: isTiltGesturesEnabled,
isRotateGesturesEnabled: isRotateGesturesEnabled,
isStopGesturesEnabled: isStopGesturesEnabled,
isUseTextureViewAndroid: isUseTextureViewAndroid,
locale: locale,
clusters: _clusters,
onScreenToCoordinate: onScreenToCoordinate,
onCoordinateToScreen: onCoordinateToScreen,
fpsLimit: fpsLimit
// locationOverlay={_locationOverlay}
,
onTapClusterLeaf: onTapClusterLeaf ? ({
nativeEvent: {
markerIdentifier
}
}) => onTapClusterLeaf({
markerIdentifier
}) : undefined,
...rest
});
});
//# sourceMappingURL=NaverMapView.js.map