///
import React, {
FC,
PropsWithChildren,
useRef,
useEffect,
useImperativeHandle,
useReducer,
useMemo,
CSSProperties,
} from 'react';
import { useMap } from './useMap';
import { Context, reducer, initialState } from './context';
export * from './useMap';
export * from './context';
export interface Control {
Control: BMap.Control;
NavigationControl: BMap.NavigationControlOptions;
OverviewMapControl: BMap.OverviewMapControlOptions;
ScaleControl: BMap.ScaleControlOptions;
MapTypeControl: BMap.MapTypeControlOptions;
CopyrightControl: BMap.CopyrightControlOptions;
GeolocationControl: BMap.GeolocationControlOptions;
}
export type ControlOptions =
| {
name: keyof Control;
options?: (bmap: typeof BMap, map: BMap.Map) => void;
control?(bmap: typeof BMap, map: BMap.Map): BMap.Control;
}
| {
name: keyof Control;
options?: Control[keyof Control];
control?(bmap: typeof BMap, map: BMap.Map): BMap.Control;
};
export type ControlOptionsAll = keyof Control | ControlOptions;
export interface MapProps extends BMap.MapOptions, BMap.MapEvents {
className?: React.HTMLAttributes['className'];
style?: React.HTMLAttributes['style'];
/**
* 指定的容器
*/
container?: HTMLDivElement | null | undefined;
/**
* 百度地图上负责与地图交互的UI元素称为控件。
*/
widget?: (ControlOptionsAll | ControlOptions)[];
/**
* 缩放等级
*/
zoom?: number;
/**
* 定位, 可使用如 `上海市` 的地区字符串,
* 也可以使用对象如 `{lng: 121.424333, lat: 31.228604}` 表示经纬度
*/
center?: string | BMap.Point;
/**
* IP定位获取当前城市,进行自动定位
*/
autoLocalCity?: boolean;
/** 设置地图默认的鼠标指针样式。参数cursor应符合CSS的cursor属性规范 */
defaultCursor?: CSSProperties['cursor'];
/**
* 启用地图拖拽,默认启用
*/
enableDragging?: boolean;
/**
* 启用滚轮放大缩小,默认禁用
*/
enableScrollWheelZoom?: boolean;
/**
* 启用双击放大,默认启用
*/
enableDoubleClickZoom?: boolean;
/**
* 启用地图惯性拖拽,默认禁用
*/
enableInertialDragging?: boolean;
/**
* 启用连续缩放效果,默认禁用
*/
enableContinuousZoom?: boolean;
/**
* 启用双指操作缩放,默认启用
*/
enablePinchToZoom?: boolean;
/**
* 启用键盘操作,默认禁用。键盘的上、下、左、右键可连续移动地图。同时按下其中两个键可使地图进行对角移动。
* PgUp、PgDn、Home和End键会使地图平移其1/2的大小。+、-键会使地图放大或缩小一级
*/
enableKeyboard?: boolean;
/**
* 设置地图个性化样式V2版本,仅支持现代浏览器(支持Canvas)
*/
mapStyleV2?: BMap.MapStyleV2;
/**
* 设置地图城市,注意当地图初始化时的类型设置为 `BMAP_NORMAL_MAP` 时,
* 需要在调用 `centerAndZoom` 之前调用此方法设置地图所在城市。
* 例如:
* @example
*
* ```js
* var map = new BMap.Map(“container”, { mapType: BMAP_NORMAL_MAP });
* map.setCurrentCity(“北京市”);
* map.centerAndZoom(new BMap.Point(116.404, 39.915), 18);
* ```
*
* 注意:初始化的坐标应与您设置的城市对应,否则地图将无法正常显示。
*/
currentCity?: string;
/**
* 将全景实例与Map类进行绑定
*/
panorama?: BMap.Panorama;
viewport?: (view: Array | BMap.Viewport, viewportOptions: BMap.ViewportOptions) => void;
children?: RenderProps['children'];
}
export type RenderProps =
| { children?: (data: { BMap: typeof BMap; map: BMap.Map; container?: HTMLDivElement | null }) => React.ReactNode }
| { children?: React.ReactNode };
export const Provider: FC> = (props) => {
const [state, dispatch] = useReducer(reducer, initialState);
return {props.children};
};
export type MapRefs = MapProps & { map?: BMap.Map; BMap?: typeof BMap; container?: HTMLDivElement | null };
export default React.forwardRef(({ className, style, children, ...props }, ref) => {
const [state, dispatch] = useReducer(reducer, initialState);
window.BMap = window.BMap || window.BMapGL;
const elmRef = useRef(null);
const { setContainer, container, setCenter, setAutoLocalCity, map } = useMap({
container: elmRef.current,
...props,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => setContainer(elmRef.current), [elmRef.current]);
// eslint-disable-next-line react-hooks/exhaustive-deps
useMemo(() => props.center && setCenter(props.center!), [props.center]);
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => setAutoLocalCity(props.autoLocalCity!), [props.autoLocalCity]);
// eslint-disable-next-line react-hooks/exhaustive-deps
useImperativeHandle(ref, () => ({ ...props, map, BMap, container: elmRef.current }), [map]);
const chields = typeof children === 'function' ? [children] : React.Children.toArray(children);
useEffect(() => {
if (map) {
dispatch({ map, container: elmRef.current, BMap });
}
}, [map]);
return (
{BMap && map && typeof children === 'function' && children({ BMap, map, container })}
{BMap &&
map &&
chields.map((child, key) => {
if (!React.isValidElement(child)) return null;
if (child.type && typeof child.type === 'string') {
return React.cloneElement(child, { key });
}
return React.cloneElement(child, {
...child.props,
BMap,
map,
container,
key,
});
})}
);
});