### 说明

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

### 特性

- 集成 高德 和 谷歌 两个地图
- 支持 vue 2.7 和 vue 3
- 统一的接口，不需要写两套

### 安装

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

```

### 加载地图样式

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

### 自定义字体

目前地图提供了 3 个字体 css variables 用于外部制定特殊字体

```css
/* 使用特殊字体 HarmonyOS_Sans_SC_Regular */
body {
  --HEYCAR_MAP_CSS_VAR_FONT_REGULAR: HarmonyOS_Sans_SC_Regular, "PingFangSC-Regular", "PingFang SC";
  --HEYCAR_MAP_CSS_VAR_FONT_MEDIUM: HarmonyOS_Sans_SC_Medium, "PingFangSC-Medium", "PingFang SC";
  --HEYCAR_MAP_CSS_VAR_FONT_SEMI_BOLD: HarmonyOS_Sans_SC_Bold, "PingFangSC-Semibold", "PingFang SC";
}
```

目前地图颜色提供了 31 个 css variables 用于外部定制颜色

```css
/* 使用 BigBoss 颜色主题 */
body {
  --HEYCAR_MAP_SVG_VAR_address-locator_linearGradient_stop_1_color: #1e1e1e;
  --HEYCAR_MAP_SVG_VAR_address-locator_linearGradient_stop_2_color: #1e1e1e;
  --HEYCAR_MAP_SVG_VAR_address-locator_linearGradient_stop_3_color: #1e1e1e;
  --HEYCAR_MAP_SVG_VAR_address-locator_linearGradient_stop_4_color: #1e1e1e;
  --HEYCAR_MAP_SVG_VAR_address-locator_path_fill: #1e1e1e;
  --HEYCAR_MAP_CSS_VAR_AbsoluteAddressBox_boxHeader_background: #1e1e1e;
  --HEYCAR_MAP_SVG_VAR_end-point_linearGradient_stop_1_color: #ff4040;
  --HEYCAR_MAP_SVG_VAR_end-point_linearGradient_stop_2_color: #ff4040;
  --HEYCAR_MAP_SVG_VAR_end-point_linearGradient_stop_3_color: #ff4040;
  --HEYCAR_MAP_SVG_VAR_end-point_path_fill: rgba(0, 0, 0, 0.5);
  --HEYCAR_MAP_SVG_VAR_waypoint_path_fill: #ff4040;
  --HEYCAR_MAP_SVG_VAR_passenger-circle_circle_fill: #1e1e1e;
  --HEYCAR_MAP_SVG_VAR_passenger-circle_outerCircle_fill: #4471ff;
  --HEYCAR_MAP_SVG_VAR_passenger-circle_outerCircle_stroke: #003dff;
  --HEYCAR_MAP_SVG_VAR_place-circle_color: #1e1e1e;
  --HEYCAR_MAP_SVG_VAR_start-point_linearGradient_stop_1_color: #00ad57;
  --HEYCAR_MAP_SVG_VAR_start-point_linearGradient_stop_2_color: #00ad57;
  --HEYCAR_MAP_SVG_VAR_start-point_path_fill: rgba(0, 0, 0, 0.5);
  --HEYCAR_MAP_SVG_VAR_wave-circle_color: #1e1e1e;
  --HEYCAR_MAP_SVG_VAR_arraw-right_color: #666666;
  --HEYCAR_MAP_CSS_VAR_AbsoluteAddressBox_boxBody_background_1: #ffffff;
  --HEYCAR_MAP_CSS_VAR_AbsoluteAddressBox_boxBody_background_2: #ffffff;
  --HEYCAR_MAP_CSS_VAR_AbsoluteAddressBox_boxBody_background_3: #ffffff;
  --HEYCAR_MAP_CSS_VAR_AbsoluteAddressBox_boxBody_background_4: #ffffff;
  --HEYCAR_MAP_CSS_VAR_AbsoluteAddressBox_boxPhotoLayout_border: #d8d8d8;
  --HEYCAR_MAP_CSS_VAR_AbsoluteAddressBox_straightLine_background: #1e1e1e;
  --HEYCAR_MAP_CSS_VAR_AbsoluteAddressBox_boxTitle_color: #1e1e1e;
  --HEYCAR_MAP_CSS_VAR_AbsoluteAddressBox_boxDescription_color: #1e1e1e;
  --HEYCAR_MAP_CSS_VAR_PlaceCircle_label_color: #1e1e1e;
  --HEYCAR_MAP_CSS_VAR_PlaceCircle_tag_background: #1e1e1e;
  --HEYCAR_MAP_CSS_VAR_StartEndPoint_pointInfoBoxEmphasize_color: #e59900;
  --HEYCAR_MAP_CSS_VAR_StartEndPoint_pointSingleInfoBox_boxShadow: rgba(78, 85, 108, 0.15);
}
```

### 使用

常用数据结构

```typescript
export type CoordinateType = "wgs84" | "gcj02" | "bd09";

export type CoordinatePoint = {
  lng: number;
  lat: number;
  type: CoordinateType;
};

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

export interface CoordinateZone {
  name: string;
  path: CoordinatePoint[];
}

export interface CoordinateRecommendZonePlaces {
  // 是否强制吸附
  adsorption?: boolean;
  type?: RecommendType;
  // 是否可以提供服务
  available?: boolean;
  zone?: CoordinateZone;
  places?: CoordinatePlace[];
}

export interface CoordinateValueOfOnChangeRecommendPlace {
  type: RecommendType;
  isSameZone: boolean;
  place: CoordinatePlace;
  inputPlace: CoordinatePlace;
  zone?: CoordinateZone;
}

export interface CoordinateGeoPosition {
  position: CoordinatePoint;
  coords?: GeolocationCoordinates;
}

export interface CoordinateTrackPoint {
  lng: number;
  lat: number;
  type: CoordinateType;
  angle?: number;
  speed?: number;
  timestamp: number;
}

export interface CoordinateExternalRoute {
  path: CoordinatePoint[];
  duration: number;
  distance: number;
}

export type GetDriverRouteOrTrackOutput =
  | {
      routes?: CoordinateExternalRoute;
      tracks?: CoordinateTrackPoint[];
    }
  | undefined;

export enum CenterPlaceStatus {
  GEO_LOADING = "GEO_LOADING",
  QUERYING_INFO = "QUERYING_INFO",
  SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
  OK = "OK",
}

export type GoogleConnectionStatus = "pending" | "connected" | "unconnected";

// 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;
}

// Restricted（绿区）Forbidden（红区）Recommend（推荐点）
export type RecommendType = "Restricted" | "Forbidden" | "Recommend";

export type DriverStatus =
  | "dispatching"
  | "book-dispatching"
  | "dispatched"
  | "driverStartService"
  | "driverStartRelayService"
  | "book-driverStartService"
  | "book-dispatched"
  | "driverArrived"
  | "inService"
  | "canceled"
  | "endService"
  | "completed"
  | "canceling"
  | "banlanceRefund"
  | "waitBanlanceRefund"
  | "rechargePayed"
  | "waitRechargePay"
  | "payed"
  | "waitpay"
  | "refund"
  | "confirmed"
  | "assign"
  | "orderReassigned";
```

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

- 对于 jsx/tsx 文件的例子

```jsx
<MapProvider
  // 高德地图 api key
  amapKey={amapApiKey}
  // 高德地图 secret
  amapSecret={amapApiSecret}
  // 谷歌地图 id
  gmapId={gmapId}
  // 谷歌地图 api key
  gmapKey={gmapApiKey}
  // 使用哪个地图供应商，目前两个供应商： amap 高德 / gmap 谷歌
  supplier={"amap"}
  // 可选，高德驾车路线规划代理地址
  gaodeDirectionDrivingProxyUrl="/overseas/amap/driveGuide"
  // 可选，高德步行路线规划代理地址
  gaodeDirectionWalkingProxyUrl="/overseas/amap/walkingGuide"
  // 可选，谷歌路线纠偏代理地址
  googleSnapRoadProxyUrl="/overseas/maps/snapToRoads"
  // 弃用，谷歌路线规划代理地址
  googleDirectionsProxyUrl="/overseas/maps/directions/json"
  // 可选，谷歌路由服务代理地址
  googleRoutesProxyUrl="/overseas/maps/routes/directions/v2"
  // 可选，自定义地图颜色
  themeVariables={
    {
      // bigBoss 主题
      // TRAFFIC_UNKNOWN_BACKGROUND_COLOR: "#1E1E1E",
      // TRAFFIC_UNKNOWN_BORDER_COLOR: "#1E1E1E",
      // TRAFFIC_NORMAL_BACKGROUND_COLOR: "#1E1E1E",
      // TRAFFIC_NORMAL_BORDER_COLOR: "#1E1E1E",
      // TRAFFIC_SLOW_BACKGROUND_COLOR: "#F9D100",
      // TRAFFIC_SLOW_BORDER_COLOR: "#B29400",
      // TRAFFIC_TRAFFIC_JAM_BACKGROUND_COLOR: "#EB0E33",
      // TRAFFIC_TRAFFIC_JAM_BORDER_COLOR: "#990D24",
      // TRAFFIC_HEAVY_TRAFFIC_JAM_BACKGROUND_COLOR: "#99001A",
      // TRAFFIC_HEAVY_TRAFFIC_JAM_BORDER_COLOR: "#4D000D",
      // TRAFFIC_DONE_BACKGROUND_COLOR: "#CCCCCC",
      // TRAFFIC_DONE_BORDER_COLOR: "#CCCCCC",
      // WALKING_LINE_COLOR: " #1E1E1E",
      // ZONE_RESTRICTED_BACKGROUND_COLOR: "rgba(153,153,153,0.1)",
      // ZONE_RESTRICTED_BORDER_COLOR: "#1E1E1E",
      // ZONE_FORBIDDEN_BACKGROUND_COLOR: "#F27878",
      // ZONE_FORBIDDEN_BORDER_COLOR: "#F41717",
      //
      // 支付宝迁移主题-图标
      // ICON_START_POINT_EN_URL: "https://<支付宝oss域名>/heycar-map/svg/0.12/start-point-en.svg";
      // ICON_END_POINT_EN_URL: "https://<支付宝oss域名>/heycar-map/svg/0.12/end-point-en.svg";
      // ICON_END_POINT_ZH_TW_URL: "https://<支付宝oss域名>/heycar-map/svg/0.12/end-point-zh-TW.svg";
      // ICON_TAXI_CAR_URL: "https://<支付宝oss域名>/heycar-map/svg/taxi-car.svg";
      // ICON_DOT_LOADING_URL: "https://<支付宝oss域名>/heycar-map/gif/dot-loading.gif";
      // ICON_LOAD_FAILED_URL: "https://<支付宝oss域名>/heycar-map/svg/load-failed.svg";
      // ICON_WAYPOINT_URL: "https://<支付宝oss域名>/heycar-map/svg/0.12/waypoint.svg";
    }
  }
  // 地图加载失败时显示的标题
  renderLoadFailedTitle={() => (supplier === "gmap" ? "未能成功访问谷歌地图" : "高德地图加载失败")}
  // 地图加载失败时显示的描述
  renderLoadFailedDescription={() =>
    supplier === "gmap" ? "请确认您的网络能正常访问谷歌地图， \n或切回高德地图" : undefined
  }
>
  ...
</MapProvider>
```

- 对于 vue 文件的例子

```vue
<MapProvider
  :gmap-id="gmapId"
  :gmap-key="gmapApiKey"
  :amap-key="amapApiKey"
  :amap-secret="amapApiSecret"
  supplier="amap"
  render-load-failed-title='() => supplier === "gmap" ? "未能成功访问谷歌地图" : "高德地图加载失败"'
  render-load-failed-description='() => supplier === "gmap" ? "请确认您的网络能正常访问谷歌地图，\n或切回高德地图" : undefined'
>
   ...
</MapProvider>
```

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

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

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

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

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

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

对于 jsx/tsx 文件的例子

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

export default defineComponent({
  setup() {
    const {
      centerPlace,
      mapContext,
      setCenterPlaceByUserSpecified,
      setCenterPlaceByUserSpecifiedInZone,
    } = useBusinessRecomendPlaceMap();
    // 演示 setCenterPlaceByUserSpecifiedInZone 的用法
    const demoForUsage = () => {
      setCenterPlaceByUserSpecifiedInZone({
        // 期望的地图中心点
        place: {
          lng: 139.56,
          lat: 35.56,
          type: "gcj02",
          name: "user specified place in zone",
          displayName: "user specified place in zone",
        },
        // 推荐点和绿区信息
        recommends: {
          // 绿区
          zone: {
            name: "zone 1",
            path: [
              { lng: 139.569, lat: 35.555, type: "gcj02" },
              { lng: 139.558, lat: 35.55, type: "gcj02" },
              { lng: 139.56, lat: 35.565, type: "gcj02" },
            ],
          },
          // 绿区内的推荐点列表
          places: [
            {
              lng: 139.56,
              lat: 35.56,
              type: "gcj02",
              name: "user specified place in zone",
              displayName: "user specified place in zone",
            },
            {
              lng: 139.562,
              lat: 35.562,
              type: "gcj02",
              name: "recommend place 2",
              displayName: "recommend place 2",
            },
          ],
        },
      });
    };
    return () => (
      <BusinessRecomendPlaceMap
        class={"demo"}
        geoLoadingTitle={"正在获取您当前的位置"}
        unavailableTitle={"当前区域暂未开通服务"}
        forbiddenTitle={"当前区域不可叫车"}
        emptyTitle={"当前位置"}
        queryingTitle={"正在获取地址信息"}
        recomendDescription={"您将在此处上车"}
        geoErrorOnceNotificationKey="BusinessReselectPlaceMap_GeoErrorOnceKey"
        defaultCenterPlace={(place) =>
          place ?? {
            lng: 139.777777,
            lat: 35.777777,
            type: "gcj02",
            name: "default place name",
            displayName: "default place displayName",
          }
        }
        // 可选，应用启动时是否跳过等待 GPS，默认 false
        skipWaitGeo={
          false ||
          true || {
            lng: 139.55555,
            lat: 35.5555,
            type: "wgs84",
            name: "skip geo place name",
            displayName: "skip geo place displayName",
          }
        }
        getAvailable={() => Promise.resolve(true)}
        getRecomendPlace={getRecomendPlace}
        getDefaultCenterPlace={getDefaultCenterPlace}
        renderPlacePhoto={(place) => {
          // or return;
          return {
            title: "图文引导",
            src: "https://oss-now.heycars.cn/image/graphicGuidance/file/hmlh38_xs6_DdksNX0_TbgF0lKXp.jpg",
          };
        }}
        renderPlaceTag={(place) => {
          // or return;
          return "最近使用";
        }}
        mapContext={mapContext}
        onChangePlace={(place) => {
          console.log("地图中心点变化时触发 place = ", place);
        }}
        onChangeRecomandPlace={({ place, inputPlace, type, zone }) => {
          console.log("用户操作地图，计算推荐点后得出的最终位置时触发，此时可以向后端查询城市信息");
          console.log(
            "计算推荐点之前的地址是: ",
            inputPlace,
            " 最终的地址是: ",
            place,
            " 推荐类型: ",
            type,
            "绿区（或红区）:",
            zone,
          );
        }}
        onClickLocatorText={() =>
          console.log("用户点击了蓝色光标文字触发，此时可以执行用户点击起点输入框相同的逻辑")
        }
        onClickLocatorPhoto={() =>
          console.log("用户点击了蓝色光标图片触发，此时可以执行用户点击起点输入框相同的逻辑")
        }
        onGeoError={({ isBusinessTimeout }) => {
          console.log(
            "获取GPS失败时触发，此时可以弹框告诉用户",
            isBusinessTimeout ? "给用户超时提示" : "给用户无权限反馈",
          );
        }}
      />
    );
  },
});
```

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

对于 jsx/tsx 文件的例子

```jsx
import { defineComponent } from "vue";
import { BusinessReselectPlaceMap, useBusinessReselectPlaceMap } from "@heycar/heycars-map";

export default defineComponent({
  setup() {
    const {
      centerPlace,
      mapContext,
      setCenterPlaceByUserSpecified,
      setCenterPlaceByUserSpecifiedInZone,
    } = useBusinessReselectPlaceMap();
    // 演示 setCenterPlaceByUserSpecifiedInZone 的用法
    const demoForUsage = () => {
      setCenterPlaceByUserSpecifiedInZone({
        // 期望的地图中心点
        place: {
          lng: 139.56,
          lat: 35.56,
          type: "gcj02",
          name: "user specified place in zone",
          displayName: "user specified place in zone",
        },
        // 推荐点和绿区信息
        recommends: {
          // 绿区
          zone: {
            name: "zone 1",
            path: [
              { lng: 139.569, lat: 35.555, type: "gcj02" },
              { lng: 139.558, lat: 35.55, type: "gcj02" },
              { lng: 139.56, lat: 35.565, type: "gcj02" },
            ],
          },
          // 绿区内的推荐点列表
          places: [
            {
              lng: 139.56,
              lat: 35.56,
              type: "gcj02",
              name: "user specified place in zone",
              displayName: "user specified place in zone",
            },
            {
              lng: 139.562,
              lat: 35.562,
              type: "gcj02",
              name: "recommend place 2",
              displayName: "recommend place 2",
            },
          ],
        },
      });
    };
    return () => (
      <BusinessReselectPlaceMap
        class={"demo"}
        unavailableTitle={"当前区域暂未开通服务"}
        forbiddenTitle={"当前区域不可叫车"}
        emptyTitle={"当前位置"}
        queryingTitle={"正在获取地址信息"}
        recomendDescription={"您将在此处上车"}
        // 对于同一个 geoErrorOnceNotificationKey
        // geoErrorOnce 事件在 geoErrorOnceNotificationInterval 时间间隔内全局只会触发一次
        geoErrorOnceNotificationKey="BusinessReselectPlaceMap"
        defaultPlace={{
          lng: 139.777777,
          lat: 35.777777,
          type: "gcj02",
          name: "default place name",
          displayName: "default place display name",
        }}
        getAvailable={() => Promise.resolve(true)}
        getRecomendPlace={async ({ lng, lat, type }) => {
          // 向后端获取推荐点信息
          return {
            // 服务是否可用
            available: true,
            // 推荐类别
            type: "Restricted",
            // 绿区
            zone: {
              name: "绿区名称",
              path: [
                { lng: lng - 0.001, lat: lat + 0.001, type },
                { lng: lng, lat: lat - 0.001, type },
                { lng: lng + 0.001, lat: lat + 0.0005, type },
              ],
            },
            // 推荐点列表
            places: [
              {
                lat: lat - 0.00001,
                lng: lng + 0.0001,
                type,
                name: "place 1",
                displayName: "place 1",
              },
              {
                lat: lat - 0.0002,
                lng: lng + 0.0002,
                type,
                name: "place 2",
                displayName: "place 2",
              },
              {
                lat: lat - 0.0002,
                lng: lng - 0.0001,
                type,
                name: "place 3",
                displayName: "place 3",
              },
            ],
          };
        }}
        onChangeRecomandPlace={({ place, inputPlace, type, zone }) => {
          console.log("用户操作地图，计算推荐点后得出的最终位置时触发，此时可以向后端查询城市信息");
          console.log(
            "计算推荐点之前的地址是: ",
            inputPlace,
            " 最终的地址是: ",
            place,
            " 推荐类型: ",
            type,
            "绿区（或红区）:",
            zone,
          );
        }}
        onClickLocatorText={() =>
          console.log("用户点击了蓝色光标文字触发，此时可以执行用户点击起点输入框相同的逻辑")
        }
        onClickLocatorPhoto={() =>
          console.log("用户点击了蓝色光标图片触发，此时可以执行用户点击起点输入框相同的逻辑")
        }
        onGeoError={({ isBusinessTimeout }) => {
          console.log(
            "获取GPS失败时触发，此时可以弹框告诉用户",
            isBusinessTimeout ? "给用户超时提示" : "给用户无权限反馈",
          );
        }}
      />
    );
  },
});
```

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

对于 jsx/tsx 文件的例子

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

export default defineComponent({
  setup() {
    const { mapContext, toAmapCoordinateType } = useBusinessQuotingMap();
    return () => (
      <div>
        <BusinessQuotingMap
          class={"demo"}
          isBezierCurve
          isNeedMapRouteData
          from={{
            displayName: "The Malayan Council",
            name: "10 Winstedt Rd, #01-17, Singapore 227977",
            type: "wgs84",
            lat: 1.311295,
            lng: 103.841974,
          }}
          to={{
            displayName: "CDG Engie Charging Station",
            name: "21 Kent Ridge Rd, Singapore 119220",
            type: "wgs84",
            lat: 1.2966426,
            lng: 103.7763939,
          }}
          fromDescription={"您将在此上车"}
          renderDescription={({ distance, duration, tolls }) =>
            `全程 *${distance / 1000}公里*  约行驶 *${duration}* 高速费用 *${tolls ?? 0}*元`
          }
          // 是否使用禁止点击样式
          // disableStartPoint
          // disableEndPoint
          mapContext={mapContext}
          onClickStartPoint={(place) => console.log("点击起点时触发 palce = ", place)}
          onClickEndPoint={(place) => console.log("点击终点时触发 palce = ", place)}
          onChangeGoogleConnection={(status) =>
            // 根据目前的产品需求，连通性检测只会被检测一次。
            console.log("谷歌连通性发生变化时触发，连通性状态是：", status)
          }
        />
        <div>
          经度 103.841974， 纬度 1.311295 在高德地图上的坐标类型是:
          {toAmapCoordinateType([103.841974, 1.311295])}
      </div>
      <div>
    );
  },
});
```

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

对于 jsx/tsx 文件的例子

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

export default defineComponent({
  setup() {
    const { mapContext } = useBusinessTaxiServiceMap();
    return () => (
      <BusinessTaxiServiceMap
        class={css.adjustedDemo}
        from={{
          displayName: "The Malayan Council",
          name: "10 Winstedt Rd, #01-17, Singapore 227977",
          type: "wgs84",
          lat: 1.311295,
          lng: 103.841974,
        }}
        to={{
          displayName: "CDG Engie Charging Station",
          name: "21 Kent Ridge Rd, Singapore 119220",
          type: "wgs84",
          lat: 1.2966426,
          lng: 103.7763939,
        }}
        relayTo={{
          displayName: "Lucky Plaza",
          name: "304 Orchard Rd, Lucky Plaza, Singapore 238863",
          type: "wgs84",
          lat: 1.3049168518726226,
          lng: 103.83369616777854,
        }}
        driverStatus={"driverArrived"}
        relayToTitle="上个乘客将\n在这下车"
        bookDispatchingTitle="2月14日 11:00 用车"
        dispatchingTitle="正在为您搜索附近司机"
        renderBookDispatchedTitle={() => "*6月12日 11:00* 用车"}
        driverArrivedTitle="司机已等待 00:35"
        renderStartSerivceTitle={({ distance, duration }) =>
          `距你*${distance}*公里, *${duration}*分钟`
        }
        renderInServiceTitle={({ distance, duration }) =>
          `距离终点*${distance}*公里, 预计*${duration}*分钟`
        }
        getDriverPositionTrack={async () => {
          //  向后端请求司机的历史轨迹
          return Promise.resolve<TrackPoint[]>([
            { lng: 121.4036983, lat: 31.216324, type: "gcj02", angle: 30, timestamp: 1698058438000 },
            { lng: 121.4036983, lat: 31.216324, type: "gcj02", angle: 30, timestamp: 1698058439000 },
            { lng: 121.403581, lat: 31.216415, type: "gcj02", angle: 30, timestamp: 1698058442000 },
          ]);
        }}
        // getDriverRouteOrTrack 与 getDriverPositionTrack 二选一
        getDriverRouteOrTrack={async () => {
          //  后端返回司机的真实导航路径或者历史轨迹
          return Promise.resolve<GetDriverRouteOrTrackOutput>({
            routes: {
              distance: 4270,
              duration: 1310,
              path: [
                {lng: 121.401554, lat: 31.21653, type: "gcj02"},
                {lng: 121.401554, lat: 31.21653, type: "gcj02"},
                {lng: 121.401795, lat: 31.21654, type: "gcj02"},
              ],
            },
          });
        }}
        interval={5000}
        mapContext={mapContext}
      />
    );
  },
});
```

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

对于 jsx/tsx 文件的例子

```jsx
import { defineComponent } from "vue";
import { BusinessTaxiEndMap } from "@heycar/heycars-map";

export default defineComponent({
  setup() {
    return () => (
      <BusinessTaxiEndMap
        class={"demo"}
        from={{
          displayName: "樟宜机场",
          name: "樟宜机场",
          lat: 1.35019,
          lng: 103.994003,
          type: "wgs84",
        }}
        to={{
          lat: 1.346493,
          lng: 103.746209,
          name: "长城美华 Coffee Shop (CCMW)",
          displayName: "长城美华 Coffee Shop (CCMW)",
          type: "wgs84",
        }}
      />
    );
  },
});
```

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

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

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

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

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

- 对于 vue 文件的例子

```vue
<HeycarMap :center="[0, 0]" class="any class name" :zoom="3">
   <template #fallback>error</template>
   <template #loading>loading</template>
   ...
   <AddressBox title="Martyrs Lawn" :position="[0, 0]" description="您将在此处上车" >
   </AddressBox>
   ...
</HeycarMap>
```

#### `HeycarMap` 的基本用法

- 对于 jsx/tsx 文件的例子

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

- 对于 vue 文件的例子

```vue
<HeycarMap :center="[0, 0]" class="any class name" :zoom="3">
   <template #fallback>error</template>
   <template #loading>loading</template>
   ...
</HeycarMap>
```

#### 关于 enableAuxiliaryGraspRoad 模式

enableAuxiliaryGraspRoad 模式适用场景：

- 测试司机位置偏移 的优化效果
- 目前只能在国内打车，测试优化效果。
- 目前只能用 splytech 供应商进行测试。

测试时的注意点：

1. 起点和终点 在 splytech 后台系统地图上的位置是错误的。

为了方便测试 司机位置偏移 的优化效果，在 enableAuxiliaryGraspRoad 模式下会显示下列辅助信息：

1. 会显示两个导航路线，蓝色跟设计稿样式一致的是原来的导航路径，红色的是司机位置纠偏以后计算的导航路径。
2. 会显示两个车辆，跟设计稿样式一致的是原来的车辆，虚影的车辆是司机位置纠偏以后的车辆。
3. 会将供应商提供的司机位置显示为蓝色标记，辅助观察供应商提供的司机位置。
4. 会显示一条黑色的路径，表示将供应商提供的位置纠偏以后的路径。
5. enableAuxiliaryGraspRoad 模式下，为了方便测试，取消了屏幕 15 秒自动调整功能。

#### 下面是地图导出的一些基本工具

```ts
import { isCoordinatePointEqual } from "@heycar/heycars-map";

// 比较两个带有坐标类型的点是否为同一个点
isCoordinatePointEqual(
  { type: "gcj02", lng: 114.215114, lat: 22.215972 },
  { type: "wgs84", lng: 114.21016180538568, lat: 22.219570659901557 },
) === true;
```

```ts
import { inChina, inHongKong, inMacau, inTaiwan, inKorean } from "@heycar/heycars-map";

// 判断某点是否在某区域内
const point = [114.215114, 22.215972];

// 是否在中国 (不包含台湾)
inChina(point);

// 是否在香港
inHongKong(point);

// 是否在澳门
inMacau(point);

// 是否在台湾
inTaiwan(point);

// 是否在韩国
inKorean(point);

// 是否在谷歌、高德地图坐标系存在差异区域
inKorean(point);
```
