Przeglądaj źródła

feat(AMap): 添加高德地图,添加路线轨迹组件

xieyonghong 3 lat temu
rodzic
commit
6d53528d8b

+ 1 - 0
package.json

@@ -88,6 +88,7 @@
     "monaco-editor-webpack-plugin": "^6.0.0",
     "omit.js": "^2.0.2",
     "react": "^17.0.0",
+    "react-amap": "^1.2.8",
     "react-dev-inspector": "^1.1.1",
     "react-dom": "^17.0.0",
     "react-helmet-async": "^1.0.4",

+ 8 - 0
src/app.tsx

@@ -250,6 +250,14 @@ export function render(oldRender: any) {
   if (history.location.pathname !== loginPath) {
     MenuService.queryOwnThree({ paging: false }).then((res) => {
       if (res && res.status === 200) {
+        if (isDev) {
+          res.result.push({
+            code: 'demo',
+            id: 'demo',
+            name: '例子',
+            url: '/demo',
+          });
+        }
         extraRoutes = handleRoutes(res.result);
         saveMenusCache(extraRoutes);
       }

+ 84 - 0
src/components/AMapComponent/PathSimplifier/index.tsx

@@ -0,0 +1,84 @@
+import { useCallback, useEffect, useRef } from 'react';
+
+interface PathSimplifierProps {
+  __map__?: any;
+  options?: Omit<PathSimplifierOptions, 'map'>;
+  pathNavigatorOptions?: PathNavigatorOptions;
+  speed?: number;
+  pathName?: string;
+  pathData?: PathDataType;
+  onCreated?: (nav: PathNavigator) => void;
+}
+
+const PathSimplifier = (props: PathSimplifierProps) => {
+  const { pathData, pathName, __map__, onCreated, speed, pathNavigatorOptions, options } = props;
+
+  const pathSimplifierRef = useRef<PathSimplifier | null>(null);
+  const pathNavRef = useRef<PathNavigator | undefined>(undefined);
+
+  const createPathNav = (path: number[][], navOptions?: PathNavigatorOptions) => {
+    pathSimplifierRef.current?.setData([
+      {
+        name: pathName,
+        path,
+      },
+    ]);
+    pathNavRef.current = pathSimplifierRef.current?.createPathNavigator(0, {
+      loop: false,
+      speed: 10000,
+      ...navOptions,
+    });
+    if (onCreated) {
+      onCreated(pathNavRef.current!);
+    }
+  };
+
+  const pathSimplifier = useCallback(
+    (PathObj: PathSimplifier) => {
+      // @ts-ignore
+      pathSimplifierRef.current = new PathObj({
+        zIndex: 100,
+        getPath: (_pathData: any) => {
+          return _pathData.path;
+        },
+        getHoverTitle: (_pathData: any) => {
+          return _pathData.name;
+        },
+        map: __map__,
+        ...options,
+      });
+      if (pathData) {
+        createPathNav(pathData, pathNavigatorOptions);
+      }
+    },
+    [props],
+  );
+
+  const loadUI = () => {
+    if ((window as any).AMapUI) {
+      (window as any).AMapUI.load(['ui/misc/PathSimplifier', 'lib/$'], (path: PathSimplifier) => {
+        if (!path.supportCanvas) {
+          console.warn('当前环境不支持 Canvas!');
+          return;
+        }
+        pathSimplifier(path);
+      });
+    }
+  };
+
+  useEffect(() => {
+    if (pathNavRef.current && speed !== undefined) {
+      pathNavRef.current?.setSpeed(speed);
+    }
+  }, [pathNavRef.current, speed]);
+
+  useEffect(() => {
+    if (__map__) {
+      loadUI();
+    }
+  }, [__map__]);
+
+  return null;
+};
+
+export default PathSimplifier;

+ 128 - 0
src/components/AMapComponent/PathSimplifier/types.d.ts

@@ -0,0 +1,128 @@
+type PathDataType = number[][];
+
+type PathSimplifierOptions = {
+  map?: any;
+  zIndex?: number;
+  data?: number[][];
+  getPath?: (pathData: {}, pathIndex: number) => PathDataType;
+  getZIndex?: (pathData: any, pathIndex: number) => number;
+  getHoverTitle?: (pathData: any, pathIndex: number, pointIndex: number) => string;
+  autoSetFitView?: boolean;
+  clickToSelectPath?: boolean;
+  onTopWhenSelected?: boolean;
+  renderConstructor?: Function;
+  renderOptions?: {};
+};
+
+class PathSimplifier {
+  constructor(options: PathSimplifierOptions);
+
+  readonly supportCanvas: boolean;
+
+  getZIndexOfPath(pathIndex: number): number;
+
+  setZIndexOfPath(pathIndex: number, zIndex: number);
+
+  /**
+   * 是否置顶显示pathIndex对应的轨迹
+   * @param pathIndex
+   * @param isTop isTop为真,设置 zIndex 为 现存最大zIndex+1; isTop为假,设置 zIndex 为 构造参数中 getZIndex 的返回值
+   */
+  toggleTopOfPath(pathIndex: number, isTop: boolean);
+
+  getPathData(pathIndex: number): any;
+
+  createPathNavigator(pathIndex: number, options: {}): PathNavigator;
+
+  getPathNavigators(): any[];
+
+  clearPathNavigators();
+
+  getSelectedPathData(): any;
+
+  getSelectedPathIndex(): number;
+
+  isSelectedPathIndex(pathIndex: number): boolean;
+
+  setSelectedPathIndex(pathIndex: number);
+
+  render();
+
+  renderLater(delay: number[]);
+
+  setData(data: any[]);
+
+  setFitView(pathIndex: number);
+
+  on(eventName: String, handler: Function);
+
+  off(eventName: String, handler: Function);
+
+  hide();
+
+  show();
+
+  isHidden(): boolean;
+
+  getRender(): boolean;
+
+  getRenderOptions(): any;
+}
+
+interface PathNavigatorOptions {
+  loop?: boolean;
+  speed?: number;
+  pathNavigatorStyle?: {};
+  animInterval?: number;
+  dirToPosInMillsecs?: number;
+  range?: number[];
+}
+
+class PathNavigator {
+  constructor(options: PathNavigatorOptions);
+
+  start(pointIndex?: number);
+
+  pause();
+
+  resume();
+
+  stop();
+
+  destroy();
+
+  getCursor(): any;
+
+  getNaviStatus(): string;
+
+  getPathIndex(): number;
+
+  getPosition(): [number, number];
+
+  getSpeed(): number;
+
+  getMovedDistance(): number;
+
+  getPathStartIdx(): number;
+
+  getPathEndIdx(): number;
+
+  moveByDistance(distance: number);
+
+  moveToPoint(idx: number, tail: number);
+
+  isCursorAtPathEnd(): boolean;
+
+  isCursorAtPathStart(): boolean;
+
+  setSpeed(speed: number);
+
+  setRange(startIndex: number, endIndex: number);
+
+  on(eventName: String, handler: Function);
+
+  off(eventName: String, handler: Function);
+}
+
+type PathNavigatorType = PathNavigator;
+type PathSimplifierType = PathSimplifier;

+ 25 - 0
src/components/AMapComponent/amap.tsx

@@ -0,0 +1,25 @@
+import React from 'react';
+import type { MapProps } from 'react-amap';
+import { Map } from 'react-amap';
+
+interface AMapProps extends MapProps {
+  style?: React.CSSProperties;
+  className?: string;
+}
+
+export default (props: AMapProps) => {
+  const { style, className, ...extraProps } = props;
+
+  // TODO 后期可以使用页面渲染时获取缓存中的key
+
+  return (
+    <div style={style || { width: '100%', height: '100%' }} className={className}>
+      {
+        // @ts-ignore
+        <Map version={'1.4.0'} {...extraProps}>
+          {props.children}
+        </Map>
+      }
+    </div>
+  );
+};

+ 2 - 0
src/components/index.ts

@@ -9,3 +9,5 @@ export { default as Modal } from './Modal';
 export { default as AIcon } from './AIcon';
 export { default as PermissionButton } from './PermissionButton';
 export { default as TitleComponent } from './TitleComponent';
+export { default as AMap } from './AMapComponent/amap';
+export { default as PathSimplifier } from './AMapComponent/PathSimplifier';

+ 40 - 0
src/pages/demo/AMap/index.tsx

@@ -0,0 +1,40 @@
+import { AMap, PathSimplifier } from '@/components';
+import { useState } from 'react';
+
+export default () => {
+  const [speed, setSpeed] = useState(10000);
+  return (
+    <AMap
+      useAMapUI={true}
+      style={{
+        height: 500,
+        width: '100%',
+      }}
+    >
+      <PathSimplifier
+        pathData={[
+          [116.405289, 39.904987],
+          [113.964458, 40.54664],
+          [111.47836, 41.135964],
+          [108.949297, 41.670904],
+          [106.380111, 42.149509],
+          [103.774185, 42.56996],
+          [101.135432, 42.930601],
+          [98.46826, 43.229964],
+          [95.777529, 43.466798],
+          [93.068486, 43.64009],
+          [90.34669, 43.749086],
+          [87.61792, 43.793308],
+        ]}
+        pathName={'线路1'}
+        speed={speed}
+        onCreated={(nav) => {
+          nav.start();
+          setTimeout(() => {
+            setSpeed(speed * 8);
+          }, 5000);
+        }}
+      />
+    </AMap>
+  );
+};

+ 3 - 0
src/utils/menu/index.ts

@@ -36,6 +36,9 @@ const extraRouteObj = {
       { code: 'Save2', name: '测试详情' },
     ],
   },
+  demo: {
+    children: [{ code: 'AMap', name: '地图' }],
+  },
 };
 
 /**