Skip to content

Commit

Permalink
feat: 地图组件重构
Browse files Browse the repository at this point in the history
  • Loading branch information
wangxingkang committed Jan 15, 2024
1 parent ad34396 commit 43bb1d6
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 72 deletions.
2 changes: 1 addition & 1 deletion src/hooks/useMap.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useContext } from 'react';
import { MapContext } from '@/context';
import { MapContext } from '../map/context';

export const useMap = () => {
const context = useContext(MapContext);
Expand Down
9 changes: 9 additions & 0 deletions src/map/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createContext } from 'react';

import type { Map } from 'mapbox-gl';

export interface MapContextValue {
map: Map;
}

export const MapContext = createContext<MapContextValue>({} as MapContextValue);
4 changes: 4 additions & 0 deletions src/map/map.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
a.mapboxgl-ctrl-logo,
.mapboxgl-ctrl-attrib.mapboxgl-compact {
display: none;
}
103 changes: 32 additions & 71 deletions src/map/map.tsx
Original file line number Diff line number Diff line change
@@ -1,88 +1,49 @@
import * as Mapbox from 'mapbox-gl';
import { forwardRef, useEffect, useRef, useState, useImperativeHandle } from 'react';
import { useBoolean } from '@pansy/react-hooks';
import { getTargetElement } from '@pansy/shared/react';
import MapboxWorker from 'mapbox-gl/dist/mapbox-gl-csp-worker';

import { MapContext } from '@/context';
import { useReact } from '@/hooks/useReact';

import { allProps, mapEventMap, setterMap, converterMap } from './config';
import mapbox from 'mapbox-gl';
import React, { useRef, useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { MapContext } from './context';

import 'mapbox-gl/dist/mapbox-gl.css';
import './map.css';

import type { MapboxOptions } from 'mapbox-gl';
import type { MapProps, EventMapping } from './types';
import type { MapContextValue } from './context';

// @ts-ignore
Mapbox['workerClass'] = MapboxWorker;
export interface MapProps {
/** 地图加载前的加载效果 */
loading?: React.ReactNode;
children?: React.ReactNode;
}

export const Map = forwardRef<Mapbox.Map, MapProps>((props, ref) => {
export const Map: React.FC<MapProps> = (props) => {
const { loading, children } = props;
const containerRef = useRef<HTMLDivElement>(null);
const [ready, readyAction] = useBoolean();
const [map, setMap] = useState<Mapbox.Map>();

const { onInstanceCreated } = useReact<MapProps, Mapbox.Map, EventMapping>(props, {
ins: map,
events: mapEventMap,
setterMap,
converterMap,
});
const [mapInstance, setMapInstance] = useState<mapbox.Map>();

useImperativeHandle(ref, () => map as Mapbox.Map, [map]);
const { current: contextValue } = useRef<MapContextValue>({} as MapContextValue);

useEffect(() => {
const container = getTargetElement(containerRef);

if (!container) return;

createInstance().then((map) => {
onInstanceCreated();

map.once('load', () => {
readyAction.setTrue();
});

setMap(map);
if (!containerRef.current) return;
let instance: mapbox.Map;

mapbox.accessToken =
'pk.eyJ1IjoienQyMDIzMTEwOSIsImEiOiJjbG9xdGgxcDMwbDAyMmpwODVrNG5seXphIn0.1xKSk8Ll-80kkEwtzfLWhw';
instance = new mapbox.Map({
container: containerRef.current,
style: 'mapbox://styles/mapbox/streets-v12',
center: [-74.5, 40],
zoom: 0,
});
}, []);

/** 创建地图实例 */
const createInstance = () => {
const options = getCreateOptions();
return Promise.resolve(new Mapbox.Map(options));
};

/** 获取创建地图的参数 */
const getCreateOptions = () => {
const container = getTargetElement(containerRef) as HTMLDivElement;

const options: MapboxOptions = {
container,
};
contextValue.map = instance;

allProps.forEach((key) => {
if (key in props) {
// @ts-ignore
options[key] = props[key];
}
instance.once('load', () => {
setMapInstance(instance);
});

return options;
};
}, [containerRef]);

return (
<MapContext.Provider value={map}>
<div ref={containerRef} style={{ height: '100%', width: '100%' }}>
{ready && props.children}
</div>
</MapContext.Provider>
<div ref={containerRef} style={{ width: 500, height: 500 }}>
{!mapInstance && loading}
{mapInstance && <MapContext.Provider value={contextValue}>{children}</MapContext.Provider>}
</div>
);
});

Map.defaultProps = {
attributionControl: false,
style: 'mapbox://styles/mapbox/navigation-preview-night-v2',
accessToken:
'pk.eyJ1IjoiYmVpamluZ3NlbnNvcm8iLCJhIjoiY2wzNDhwMGU2MDAxdzNkbXB2eG5qcGJ4bSJ9.9YrZb00BwBNTsfMTdgj-oA',
};

0 comments on commit 43bb1d6

Please sign in to comment.