npm package: @heycar/heycars-map-react
Description: 时间关系，先写个简要文档，之后会补一个全面的文档。
Latest version: 0.5.1

### 说明

时间关系，先写个简要文档，之后会补一个全面的文档。

### 安装

```bash
# 安装依赖包
npm install @heycar/heycars-map-react --save

```

### 加载地图样式

```typescript
import "@heycar/heycars-map-react/dist/style.css";
```

### 使用

目前有下列常用数据结构

```typescript
export type Language = "en" | "zh" | "zh-TW";

export type Point = [number, number];

export type Place = {
  lng: number;
  lat: number;
  name: string;
  displayName: string;
};

export interface Zone {
  name: string;
  path: Point[];
}

export interface RecommendZonePlaces {
  // 是否强制吸附
  adsorption?: boolean;
  // 是否强制推荐点, 该字段暂时停用
  force?: boolean;
  // 是否可以提供服务
  available?: boolean;
  zone?: Zone;
  places?: Place[];
}

export type DriverStatus =
  | "SUBMIT"
  | "RE_PUSH_VEHICLE"
  | "CONFIRM_NOCAR"
  | "CONFIRM"
  | "SET_OUT"
  | "ARRIVE"
  | "DRIVING"
  | "WAIT_PAY"
  | "PAYED"
  | "DELIVERED"
  | "CANCEL_BY_CS"
  | "CANCEL_BY_USER"
  | "CANCEL_CONFIRMED";

// 上车点文字可以是
// title =
//    centerPlaceStatus === CenterPlaceStatus.GEO_LOADING ? '正在获取您当前的位置' :
//    centerPlaceStatus === CenterPlaceStatus.SERVICE_UNAVAILABLE ? '当前区域暂未开通服务' :
//    centerPlace.displayName
export enum CenterPlaceStatus {
  GEO_LOADING = "GEO_LOADING",
  QUERYING_INFO = "QUERYING_INFO",
  SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
  OK = "OK",
}

// GeolocationPositionError 类型参考 [MDN Reference](https://developer.mozilla.org/docs/Web/API/GeolocationPositionError)
export interface BusinessGeolocationPositionError extends GeolocationPositionError {
  // isBusinessTimeout 是产品定义的 业务超时，不同于标准 GeolocationPositionError 的TIMEOUT
  // 参考 http://p.heycars.cn/zentaopms/www/index.php?m=story&f=view&storyID=1212
  // 参考 https://doc.weixin.qq.com/doc/w3_AZIAowasAIcGieCNESnQZe1rhTyaK?scode=ACcAmge7AAou1TTqYiAZIAowasAIc
  isBusinessTimeout: boolean;
}
```

#### 在 入口文件添加 `MapProvider`

- 对于 jsx/tsx 文件的例子

```jsx
<MapProvider
  // 高德地图 api key
  amapKey={amapApiKey}
  // 高德地图 secret
  amapSecret={amapApiSecret}
  // 谷歌地图 id
  gmapId={gmapId}
  // 谷歌地图 api key
  gmapKey={gmapApiKey}
  // 使用哪个地图供应商，目前两个供应商： amap 高德 / gmap 谷歌
  supplier={"amap"}
  // 地图语言 "en" | "zh" | "zh-TW"
  language={"zh"}
>
  ...
</MapProvider>
```

#### 在地图里可以使用的组件

为了方便集成，已经将常用业务逻辑集成在四个业务组件里面，下面是推荐使用的业务组件

- `BusinessRecomendPlaceMap`
- `BusinessQuotingMap`
- `BusinessTaxiServiceMap`
- `BusinessTaxiEndMap`

下面三个是推荐搭配使用的业务 hooks

- `useBusinessRecomendPlaceMap`
- `useBusinessQuotingMap`
- `useBusinessTaxiServiceMap`

#### 选择上车点和推荐点的地图组件 `BusinessRecomendPlaceMap`

```jsx
import { useBusinessRecomendPlaceMap, BusinessRecomendPlaceMap } from "@heycar/heycars-map-react";

function DemoForBusinessRecomendPlaceMap() {
  const { mapContext, centerPlace, setCenterPlaceByUserSpecified } = useBusinessRecomendPlaceMap();
  return (
    <BusinessRecomendPlaceMap
      className={"demo"}
      geoLoadingTitle={"正在获取您当前的位置"}
      unavailableTitle={"当前区域暂未开通服务"}
      emptyTitle={"当前位置"}
      queryingTitle={"正在获取地址信息"}
      recomendDescription={"您将在此处上车"}
      getRecomendPlace={async ({ lng, lat }) => {
        // 获取推荐点。如果没有数据，可以返回 undefined
        return {
          available: true,
          zone: {
            name: "香港迪斯尼乐园",
            path: [
              [lng - 0.001, lat + 0.001],
              [lng, lat - 0.001],
              [lng + 0.001, lat + 0.0005],
            ],
          },
          places: [
            { lat: lat - 0.00001, lng: lng + 0.0001, name: "place 1", displayName: "place 1" },
            { lat: lat - 0.0002, lng: lng + 0.0002, name: "place 2", displayName: "place 2" },
            { lat: lat - 0.0002, lng: lng - 0.0001, name: "place 3", displayName: "place 3" },
          ],
        };
      }}
      defaultCenterPlace={
        (place) => place ?? ({ lng: 116.397477, lat: 39.908692 } as Place) // 北京
      }
      renderPlacePhoto={(place) => {
        place;
        return "https://oss-now.heycars.cn/image/graphicGuidance/file/hmlh38_xs6_DdksNX0_TbgF0lKXp.jpg";
        // return place.graphicPhotoUrl;
      }}
      renderPlaceTag={(place) => {
        place;
        return "最近使用";
        // switch(place.reqFrom) {
        //   case 'Recent': '最近使用';
        //   case 'Frequent': '曾经使用';
        //   default: return;
        // };
      }}
      onChangePlace={() =>
        console.log("用户操作地图，导致地址变更时触发，此时可以向后端查询城市信息")
      }
      onClickLocatorText={() =>
        console.log("用户点击了蓝色光标触发，此时可以执行用户点击起点输入框相同的逻辑")
      }
      onClickLocatorPhoto={() =>
        console.log("用户点击了蓝色光标图片触发，此时可以跳转到图文指引")
      }
      onGeoError={({ isBusinessTimeout }) => {
        console.log(
          "获取GPS失败时触发，此时可以弹框告诉用户",
          isBusinessTimeout ? "给用户超时提示" : "给用户无权限反馈",
        );
      }}
      mapContext={mapContext}
    />
  );
}
```

#### 询价业务的地图组件 `BusinessQuotingMap`

```jsx
import { useBusinessQuotingMap, BusinessQuotingMap } from "@heycar/heycars-map-react";

function DemoForBusinessQuotingMap() {
  const { setMap, registerFitVeiw } = useBusinessQuotingMap();
  return (
    <BusinessQuotingMap
      className={"demo"}
      to={{ name: "深圳宝安国际机场", displayName: "深圳宝安国际机场",, lat: 22.625687, lng: 113.81147 }}
      from={{ name: "香港国际机场", displayName: "香港国际机场",, lat: 22.308527, lng: 113.91851 }}
      waypointCandidates={[
        [113.950999, 22.490871],
        [113.980826, 22.448231],
      ]}
      fromDescription={"您将在此上车"}
      renderDescription={({ distance, duration }) =>
        `全程 *${distance / 1000}公里*  约行驶 *${duration}*`
      }
      mapRef={setMap}
      registerOverlay={registerFitVeiw}
      onClickPlaceFrom={() => console.log("用户点击起点图标时触发")}
      onClickPlaceTo={() => console.log("用户点击终点图标时触发")}
      onChangeDrivingRoute={({ distance, duration }) =>
        console.log(`驾车路线变更时触发： ${distance}米 ${duration}秒`)
      }
    />
  );
}
```

#### 打车状态流转业务的地图组件 `BusinessTaxiServiceMap`

```jsx
import {
  useBusinessTaxiServiceMap,
  BusinessTaxiServiceMap,
  DriverStatus,
} from "@heycar/heycars-map-react";

function DemoForBusinessTaxiServiceMap() {
  const { setMap, registerFitVeiw } = useBusinessTaxiServiceMap();
  const status: DriverStatus = "dispatching";
  return (
    <BusinessTaxiServiceMap
      className={css.adjustedDemo}
      from={from}
      to={to}
      driverStatus={status}
      submitTitle="2月14日 11:00 用车"
      confirmNoCarTitle="出发前1小时可见司机位置"
      arriveTitle="司机已等待 00:35"
      renderSetOutTitle={({ distance, duration }) => `距你*${distance}*公里, *${duration}*分钟`}
      renderDrivingTitle={({ distance, duration }) =>
        `距离终点*${distance}*公里, 预计*${duration}*分钟`
      }
      getDriverPosition={async () => {
        //  向后端请求司机位置和车头方向
        return { position: [121.4136983, 31.216324] as Point, angle: 30 }
      }}
      interval={5000}
      mapRef={setMap}
      registerOverlay={registerFitVeiw}
      onChangeDrivingRoute={({ distance, duration }) =>
        console.log(`当行驶路线变更时触发，行程${distance}米，${duration}秒`)
      }
    />
  );
}
```

#### 服务结束的地图组件

```jsx
<BusinessTaxiEndMap
  className={"demo"}
  to={{ name: "深圳宝安国际机场", displayName: "深圳宝安国际机场",, lat: 22.625687, lng: 113.81147 }}
  from={{ name: "香港国际机场", displayName: "香港国际机场",, lat: 22.308527, lng: 113.91851 }}
  waypointCandidates={[
    [113.950999, 22.490871],
    [113.980826, 22.448231],
  ]}
/>
```

#### 公交车站地图组件

```jsx
<BusinessBusStationMap className={"demo"} position={[103.994003, 1.35019]} title={"公交车站xxx"} />
```

#### 海外接送机司机区域地图组件

```jsx
<BzShuttleTaxiRangeMap
  className={"demo"}
  path={[
    [139.569, 35.555],
    [139.558, 35.55],
    [139.56, 35.565],
  ]}
  /* 是否打印内部状态信息 */
  log
/>
```

#### 下面是基础业务组件的使用方法，但是目前阶段不推荐使用

下列是一些更加基础的业务组件， 虽然导出了，但是目前阶段不推荐使用

- `AbsoluteAddressBox`
- `DrivingLine`
- `PassengerCircle`
- `PlaceCircle`
- `StartEndPoint`
- `TaxiCar`
- `WalkingLine`
- `WaveCircle`
- `DrivingRoute`
- `WalkingRoute`
- `PickupPoints`

#### 在地图里使用 `AbsoluteAddressBox` ，需要放在 `HeycarMap` 内部

```jsx
<HeycarMap center={[0, 0]} zoom={3}>
  ...
  <AbsoluteAddressBox position={[0, 0]} title={"Martyrs Lawn"} description={"您将在此处上车"} />
  ...
</HeycarMap>
```

#### 在需要用到地图的地方添加 `HeycarMap`

- 对于 jsx/tsx 文件的例子

```jsx
<HeycarMap
  class="any class name"
  // 地图加载失败要显示的内容
  fallback={<div>error</div>}
  // 地图还没有加载完成时要显示的内容
  loading={<div>loading</div>}
  // 地图中心点
  center={[0, 0]}
  // 地图放缩
  zoom={3}
>
  ...
</HeycarMap>
```