# @zhangdali1996/lr-map-viewer

`@zhangdali1996/lr-map-viewer` 是面向 Vue 3 项目的三维地图组件库，提供龙软三维场景承载能力，以及基于组件实例的视角控制与模型信息查询能力。

主要能力：

- 支持 Vue 3 项目中以组件方式挂载二维图纸容器。
- 支持 Vue 3 项目中以组件方式挂载三维地图容器。
- 支持 `2d / 3d` 模式切换与统一壳层承载。
- 支持龙软三维 SDK 的运行时加载。
- 支持通过运行时配置传入二维图纸参数。
- 支持通过运行时配置传入云 GIS 参数。
- 支持通过运行时配置显式传入三维场景 `basePoint`。
- 支持按需显示区域显隐面板、调试面板和监测点面板。
- 支持通过组件实例调用 `moveView(x, y, z)` 移动三维视角。
- 支持通过组件实例保存/恢复视角，以及控制演示人员的初始化、运动和聚焦。
- 支持通过组件实例注册 `registerModelInfoQuery(callback)` 查询点击模型信息。

## 安装

```bash
npm install @zhangdali1996/lr-map-viewer
```

`vue` 和 `element-plus` 作为 `peerDependencies` 提供，要求使用方项目自行安装。

二维图纸依赖的 `@longruan/lr-map` 已随当前组件库构建产物内置，客户项目安装本包时不需要再额外访问公司内网 npm 拉取这个依赖。

安装后请显式引入组件库样式：

```js
import '@zhangdali1996/lr-map-viewer/style.css'
```

说明：

- 这部分样式对应组件库自身的布局、面板、占位态等 UI。
- 龙软 SDK 的 `/editorapp`、`/resource` 静态资源及其中的样式，仍需由实施方单独提供。

## 静态资源放置

该包不会携带龙软 SDK 的大体积静态资源。以下目录需要由实施方单独提供给客户：

- `editorapp`
- `resource`

推荐放置到客户项目的 `public` 目录：

```text
public/
  editorapp/
  resource/
```

对应默认访问路径：

- `/editorapp/editorapp.bundle.js`
- `/resource/js/three.min.js`
- `/resource/js/vue.2.6.11.js`
- `/resource/js/element_ui.js`
- `/resource/js/jquery-3.1.1.min.js`

如果客户项目的静态资源目录不是根路径，需要通过 `lr3dConfig.sdk` 自定义覆盖路径。

如果客户项目把龙软静态资源统一挂在某个业务前缀下，可以通过组件入参 `resource-prefix` 传入，让组件自动给默认的 `/editorapp` 和 `/resource` 路径补前缀。

例如：

```vue
<LrMapViewer resource-prefix="gkpt" />
```

会自动解析为：

- `/gkpt/editorapp/editorapp.bundle.js`
- `/gkpt/resource/js/three.min.js`
- `/gkpt/resource/js/vue.2.6.11.js`
- `/gkpt/resource/js/element_ui.js`
- `/gkpt/resource/js/jquery-3.1.1.min.js`

说明：

- 不传 `resource-prefix` 时，默认仍然使用 `/editorapp` 和 `/resource`
- 支持传 `gkpt`、`/gkpt`、`gkpt/`、`/gkpt/`，最终都会归一化为 `/gkpt`
- 如果你已经显式传了完整的 `sdk.scriptSrc` 或 `sdk.dependencies[].src`，则建议直接传最终路径

## 最小接入示例

### 三维示例

```vue
<script setup>
import '@zhangdali1996/lr-map-viewer/style.css'
import { LrMapViewer } from '@zhangdali1996/lr-map-viewer'

const credentialKey = 'your_credential_key'

const lr3dConfig = {
  // 是否在场景初始化成功后自动加载云 GIS 数据
  autoLoad: true,
  cloud: {
    // 数据源 guid
    dsGuid: 'your_ds_guid',
    // 三维场景基点
    basePoint: {
      x: 37517614.46684,
      y: 4410289.679932,
      z: 972.148557,
    },
    // 需要加载的巷道图层名
    layers: ['your_lane_layer_name'],
    laneSize: {
      // 巷道渲染宽度
      width: 10,
      // 巷道渲染高度
      height: 10,
    },
  },
}
</script>

<template>
  <div style="height: 100vh;">
    <LrMapViewer :lr3d-config="lr3dConfig" :credential-key="credentialKey" />
  </div>
</template>
```

### 二维图纸示例

```vue
<script setup>
import '@zhangdali1996/lr-map-viewer/style.css'
import { LrMapViewer } from '@zhangdali1996/lr-map-viewer'

const credentialKey = 'your_credential_key'

const map2dConfig = {
  behavior: {
    autoInitLayer: true,
    autoShowLayer: true,
    captureLayerTree: true,
  },
  options: {
    ygis_dsGuid: 'your_ds_guid',
    layerName: 'your_layer_name',
    layerCode: '',
  },
}
</script>

<template>
  <div style="height: 100vh;">
    <LrMapViewer
      mode="2d"
      :modes="['2d']"
      :map2d-config="map2dConfig"
      :credential-key="credentialKey"
    />
  </div>
</template>
```

### 二维三维切换示例

```vue
<script setup>
import { ref } from 'vue'
import '@zhangdali1996/lr-map-viewer/style.css'
import { LrMapViewer } from '@zhangdali1996/lr-map-viewer'

const activeMode = ref('2d')
const credentialKey = 'your_credential_key'

const map2dConfig = {
  options: {
    ygis_dsGuid: 'your_ds_guid',
    layerName: 'your_layer_name',
  },
}

const lr3dConfig = {
  autoLoad: true,
  cloud: {
    dsGuid: 'your_ds_guid',
    basePoint: {
      x: 37517614.46684,
      y: 4410289.679932,
      z: 972.148557,
    },
    layers: ['your_lane_layer_name'],
  },
}
</script>

<template>
  <div style="height: 100vh;">
    <LrMapViewer
      :mode="activeMode"
      :modes="['2d', '3d']"
      :map2d-config="map2dConfig"
      :lr3d-config="lr3dConfig"
      :credential-key="credentialKey"
    />
  </div>
</template>
```

如果你需要默认显示右上角区域显隐面板和调试面板：

```vue
<LrMapViewer
  :lr3d-config="lr3dConfig"
  :credential-key="credentialKey"
  :show-region-panel="true"
  :show-debug-panel="true"
/>
```

说明：

- 三维组件已内置默认的 `sdk`、`scene`、`initOptions`、`dataSource.type`、`dataSource.loadMode` 配置，通常不需要手动传入。
- 推荐只传 `autoLoad` 和 `cloud` 下的业务参数即可。
- 如果你有特殊需求，仍然可以继续传完整的 `lr3dConfig` 结构来覆盖默认值。

## 推荐接入方式

推荐直接按需引入组件：

```js
import { LrMapViewer } from '@zhangdali1996/lr-map-viewer'
```

也支持作为插件安装：

```js
import { createApp } from 'vue'
import LrMapViewerPlugin from '@zhangdali1996/lr-map-viewer'
import App from './App.vue'

createApp(App).use(LrMapViewerPlugin).mount('#app')
```

## 命名导出

除默认导出的插件对象外，包入口还提供以下命名导出：

- 组件：`LrMapViewer`、`Lr2dViewer`、`Lr3dViewer`
- 2D 配置工具：`getDefaultLr2dConfig`、`getLr2dConfig`、`getLr2dMapOptions`、`setLr2dConfig`、`resetLr2dConfig`、`resolveLr2dConfig`、`getMissingLr2dOptionFields`、`getRequiredLr2dOptionFields`、`isLr2dConfigReady`
- 3D 配置工具：`getDefaultLr3dConfig`、`getLr3dConfig`、`setLr3dConfig`、`resetLr3dConfig`、`resolveLr3dConfig`
- 模式工具：`getSupportedMapModes`、`normalizeMapMode`、`resolveMapModes`、`resolveInitialMapMode`、`canSwitchMapMode`
- 2D/3D 适配与数据方法：同时导出 `adapters/lr2d`、`adapters/lr3d` 和 `services/gis` 中的方法，适合在需要直接操作底层地图实例或手动加载云 GIS 数据时使用

## 公开能力

组件 Props：

- `mode`
  当前激活模式，支持 `2d` 或 `3d`。
- `modes`
  当前组件允许启用的模式列表，默认 `['3d']`。
- `map2dConfig`
  二维图纸运行时配置。
- `lr3dConfig`
  龙软三维运行时配置。
- `resourcePrefix`
  三维静态资源业务前缀，用于统一给默认 `/editorapp` 与 `/resource` 路径补前缀。
- `credentialKey`
  内部凭证解密 Key，二维与三维都会使用它解析内置认证信息。
- `showRegionPanel`
  是否显示区域显隐面板，默认 `false`。
- `showDebugPanel`
  是否显示调试面板，默认 `false`。
- `showMonitorPanel`
  是否显示监测点面板，默认 `false`。

组件事件：

- `mode-change`
  当前显示模式切换时触发，回调参数结构如下：

```js
{
  mode: '2d' | '3d',
  previousMode: '2d' | '3d',
  supportedModes: ['2d', '3d'],
}
```

组件 expose：

- `switchMode(mode)`
- `getCurrentMode()`
- `getCurrentEngine()`
- `get2dInstance()`
- `get3dInstance()`
- `resize()`
- `refreshScene()`
- `registerModelInfoQuery(callback)`

说明：

- `switchMode(mode)` 支持在 `2d / 3d` 间切换当前显示引擎。
- `get2dInstance()` 返回当前二维 adapter 实例，其中包含 `map`、`options`、`behavior`、`layerTree` 等信息。
- `refreshScene()` 仅对三维场景有效。
- `registerModelInfoQuery(callback)` 会在用户点击三维中的模型对象时触发回调。
- 模型信息查询返回 4 个字段：`id`、`name`、`layerName`、`position`。

## 监测点模块

监测点相关能力通过组件实例提供，适合业务侧自己实现外部按钮、列表和联动逻辑。

监测点模块 expose：

- `initMonitorPoints()`
- `queryMonitorPointList()`
- `reloadMonitorPoints()`
- `enterScene(sceneId)`
- `focusMonitorPoint(target)`
- `focusPerson(target)`
- `movePerson(target)`
- `moveCar(target)`
- `stopPersonTrackPlayback(target)`
- `stopCarTrackPlayback(target)`
- `followPersonTrack(target)`
- `stopPersonTrackFollow(target)`
- `followCarTrack(target)`
- `stopCarTrackFollow(target)`

说明：

- `initMonitorPoints()` 用于初始化监测点，组件会查询监测点数据并加载显示到三维场景中。
- `queryMonitorPointList()` 会重新查询最新监测点数据，并返回列表结果，但不会把结果重新加载到地图上。
- `reloadMonitorPoints()` 会先清空当前场景中已加载的监测点，再重新查询并加载，避免重复添加。
- `enterScene(sceneId)` 用于按场景 `id` 切换到指定场景；内部会复用现有场景进入流程，执行视角切换、监测点刷新和场景开始通知。
- `focusMonitorPoint(target)` 会将视口移动到指定监测点，并打开该监测点的信息弹窗；`target` 支持传监测点 `id` 或监测点对象。
- `focusPerson(target)` 用于聚焦指定人员定位对象；`target` 支持传人员 `sceneId`、人员名称或人员对象，不传时默认聚焦第一名人员。
- `movePerson(target)` 用于查询并开始播放指定人员轨迹；`target` 的传参规则与 `focusPerson(target)` 保持一致。
- `moveCar(target)` 用于查询并开始播放指定车辆轨迹；`target` 支持传车辆 `sceneId`、带 `car_` 前缀的人员卡号、车辆名称或车辆对象。
- `stopPersonTrackPlayback(target)` 用于停止指定人员轨迹播放，并恢复到当前实时定位位置；`target` 的传参规则与 `focusPerson(target)` 保持一致。
- `stopCarTrackPlayback(target)` 用于停止指定车辆轨迹播放，并恢复到当前实时定位位置；`target` 支持传车辆 `sceneId`、带 `car_` 前缀的人员卡号、车辆名称或车辆对象。
- `followPersonTrack(target)` 用于开启指定人员的视角跟随，不会自动启动轨迹播放。
- `stopPersonTrackFollow(target)` 用于停止指定人员的视角跟随，不会停止轨迹播放。
- `followCarTrack(target)` 用于开启指定车辆的视角跟随，不会自动启动轨迹播放。
- `stopCarTrackFollow(target)` 用于停止指定车辆的视角跟随，不会停止轨迹播放。

## 视角控制模块

视角控制相关能力同样通过组件实例提供，便于业务侧自己实现“视角列表 + 当前视口保存恢复”。

视角控制模块 expose：

- `getViewPointList()`
- `switchToViewPoint(target)`
- `getCurrentViewInfo()`
- `applyViewInfo(viewInfo)`

说明：

- `getViewPointList()` 返回当前预设视角列表，列表项包含 `key`、`name`、`cameraPos`、`viewCenter`。
- `switchToViewPoint(target)` 用于切换到指定预设视角；`target` 支持传预设视角 `key`、视角名称或视角对象。
- `getCurrentViewInfo()` 用于读取当前视口的视角信息，返回结果可直接作为 `applyViewInfo(viewInfo)` 的入参。
- `applyViewInfo(viewInfo)` 用于按传入的视角参数恢复视口位置和视角中心。

## 其他 3D 方法

以下方法继续保留，主要用于兼容现有接入方式或演示人员联动：

- `initializeDemoPerson()`
- `startDemoPersonMotion(x, y, z)`
- `stopDemoPersonMotion()`
- `toggleDemoPersonMotion(x, y, z)`
- `focusDemoPerson()`
- `moveView(x, y, z)`

说明：

- `initializeDemoPerson()` 用于初始化人员演示对象或人员轨迹对象。
- `startDemoPersonMotion()`、`stopDemoPersonMotion()`、`toggleDemoPersonMotion()` 为旧的人员演示控制方法。
- `focusDemoPerson()` 用于聚焦当前主人员对象。
- `moveView(x, y, z)` 用于按绝对坐标快速聚焦目标点。

## 范围选点模块

范围选点相关能力单独通过组件实例提供，适合外部业务系统自己实现按钮、面板和联动逻辑，而不是依赖组件内部调试面板。

范围选点模块 expose：

- `startRangeSelection(options)`
- `cancelRangeSelection(options)`
- `setRangeSelection(center, options)`
- `setRangeSelectionByCoordinate(center, options)`
- `setRangeSelectionRadius(radius)`
- `clearRangeSelection()`
- `getRangeSelectionResult()`
- `registerRangeSelectionChange(callback)`
- `focusMonitorPoint(target)`

说明：

- `startRangeSelection(options)` 用于启动范围选点，支持通过 `options.radius` 指定初始半径。
- `cancelRangeSelection(options)` 用于取消当前范围选点，可通过 `options.preserveCurrentResult` 控制是否保留当前结果。
- `setRangeSelection(center, options)` 用于直接传入三维坐标生成球形范围，适合业务系统通过外部坐标直接驱动范围选点。
- `setRangeSelectionByCoordinate(center, options)` 用于通过外部接口传入坐标生成球形范围，内部复用 `setRangeSelection` 的范围绘制、测点过滤和回调链路。
- `setRangeSelectionRadius(radius)` 用于更新当前范围半径；如果当前已完成选点，会同步更新球体和范围内测点。
- `clearRangeSelection()` 用于清除当前范围球、选点标记和测点过滤结果。
- `getRangeSelectionResult()` 返回当前范围选点结果，包含状态、半径、球心坐标、当前巷道信息和范围内测点列表。
- `registerRangeSelectionChange(callback)` 会在开始选点、选点完成、半径变化、取消、清除时触发回调。
- `focusMonitorPoint(target)` 用于定位并打开指定测点的信息窗，支持传测点 `id` 或测点对象。

## 二维图纸配置说明

推荐写法：

```js
const map2dConfig = {
  behavior: {
    autoInitLayer: true,
    autoShowLayer: true,
    captureLayerTree: true,
  },
  options: {
    ygis_dsGuid: 'your_ds_guid',
    ygis_url: 'https://your-cloud-gis-server/',
    Url: 'https://your-map-server/',
    layerName: 'your_layer_name',
    layerCode: '',
    token: 'your_token',
    extent: '',
    rotate: false,
    animate: false,
    zoomAnimation: false,
    markerZoomAnimation: false,
    fadeAnimation: false,
  },
}
```

推荐接入方式分为两种：

- 通过 `credentialKey` 接入：
  组件会自动补齐 `ygis_url`、`map_server_url/Url`、`ygis_username`、`ygis_password`，此时你通常只需要传业务相关字段，例如 `ygis_dsGuid`、`layerName`、`layerCode`。
- 不通过 `credentialKey`，直接手动传完整二维配置：
  需要自行补齐地址和认证信息。

手动直传完整二维配置时的必填字段：

- `map2dConfig.options.ygis_dsGuid`
  二维图纸数据源 guid。
- `map2dConfig.options.ygis_url`
  云 GIS 服务地址。
- `map2dConfig.options.Url`
  二维地图服务地址。
- `map2dConfig.options.token`
  二维认证 token，和用户名密码二选一。

认证兼容说明：

- 如果没有 `token`，则需要同时传入 `map2dConfig.options.ygis_username` 和 `map2dConfig.options.ygis_password`。
- `map2dConfig.options.map_server_url` 与 `map2dConfig.options.Url` 在组件内部会自动对齐，二者传一个即可。
- 当 `map2dConfig.behavior.autoShowLayer` 为 `true` 时，`map2dConfig.options.layerName` 也属于必填项。

常用可选字段：

- `map2dConfig.options.layerCode`
  图层编码，默认可传空字符串。
- `map2dConfig.options.extent`
  初始范围。
- `map2dConfig.behavior.autoInitLayer`
  是否自动初始化图层，默认 `true`。
- `map2dConfig.behavior.autoShowLayer`
  是否自动显示指定图层，默认 `true`。
- `map2dConfig.behavior.captureLayerTree`
  是否抓取图层树，默认 `true`。

## 接口示例

推荐通过 `ref` 调用组件实例方法：

### 监测点模块示例

```vue
<script setup>
import { ref } from 'vue'
import { LrMapViewer } from '@zhangdali1996/lr-map-viewer'

const viewerRef = ref(null)

async function handleInitMonitorPoints() {
  await viewerRef.value?.initMonitorPoints?.()
}

async function handleReloadMonitorPoints() {
  await viewerRef.value?.reloadMonitorPoints?.()
}

async function handleQueryMonitorPoints() {
  const list = await viewerRef.value?.queryMonitorPointList?.()
  console.log('monitor points', list)
}

function handleFocusMonitorPoint() {
  viewerRef.value?.focusMonitorPoint?.('mock-monitor-point-1')
}

function handleFocusPerson() {
  viewerRef.value?.focusPerson?.()
}

function handleMovePerson() {
  viewerRef.value?.movePerson?.()
}
</script>

<template>
  <div style="height: 100vh;">
    <button type="button" @click="handleInitMonitorPoints">初始化监测点</button>
    <button type="button" @click="handleReloadMonitorPoints">重新加载监测点</button>
    <button type="button" @click="handleQueryMonitorPoints">查询监测点</button>
    <button type="button" @click="handleFocusMonitorPoint">聚焦监测点</button>
    <button type="button" @click="handleFocusPerson">聚焦人员</button>
    <button type="button" @click="handleMovePerson">人员移动</button>
    <LrMapViewer ref="viewerRef" :lr3d-config="lr3dConfig" />
  </div>
</template>
```

### 视角控制模块示例

```vue
<script setup>
import { ref } from 'vue'
import { LrMapViewer } from '@zhangdali1996/lr-map-viewer'

const viewerRef = ref(null)
const currentViewInfo = ref(null)

function handleSwitchViewPoint() {
  viewerRef.value?.switchToViewPoint?.('井口')
}

function handleCaptureViewInfo() {
  currentViewInfo.value = viewerRef.value?.getCurrentViewInfo?.() ?? null
}

function handleRestoreViewInfo() {
  if (currentViewInfo.value) {
    viewerRef.value?.applyViewInfo?.(currentViewInfo.value)
  }
}
</script>

<template>
  <div style="height: 100vh;">
    <button type="button" @click="handleSwitchViewPoint">切换到井口视角</button>
    <button type="button" @click="handleCaptureViewInfo">读取当前视口</button>
    <button type="button" @click="handleRestoreViewInfo">按视角参数恢复</button>
    <LrMapViewer ref="viewerRef" :lr3d-config="lr3dConfig" />
  </div>
</template>
```

### 范围选点模块示例

如果你需要通过组件实例控制范围选点：

```vue
<script setup>
import { ref, watch } from 'vue'
import { LrMapViewer } from '@zhangdali1996/lr-map-viewer'

const viewerRef = ref(null)

function startRangeSelection() {
  viewerRef.value?.startRangeSelection?.({
    radius: 500,
  })
}

function setRangeSelectionByCoordinate() {
  viewerRef.value?.setRangeSelectionByCoordinate?.(
    { x: 37515615.6365, y: 4412429.261443, z: 1270.872 },
    { radius: 500 },
  )
}

function clearRangeSelection() {
  viewerRef.value?.clearRangeSelection?.()
}

function focusFirstMonitorPoint() {
  const result = viewerRef.value?.getRangeSelectionResult?.()
  const firstMonitorPoint = result?.monitorPoints?.[0]

  if (firstMonitorPoint) {
    viewerRef.value?.focusMonitorPoint?.(firstMonitorPoint)
  }
}

watch(
  viewerRef,
  (viewer) => {
    if (!viewer?.registerRangeSelectionChange) {
      return
    }

    viewer.registerRangeSelectionChange((payload) => {
      console.log('range selection', payload)
    })
  },
  { immediate: true },
)
</script>

<template>
  <div style="height: 100vh;">
    <button type="button" @click="startRangeSelection">开始范围选点</button>
    <button type="button" @click="setRangeSelectionByCoordinate">按坐标生成范围</button>
    <button type="button" @click="clearRangeSelection">清除范围</button>
    <button type="button" @click="focusFirstMonitorPoint">定位首个测点</button>
    <LrMapViewer ref="viewerRef" :lr3d-config="lr3dConfig" />
  </div>
</template>
```

如果你需要切换二维与三维模式：

```vue
<script setup>
import { ref } from 'vue'
import { LrMapViewer } from '@zhangdali1996/lr-map-viewer'

const viewerRef = ref(null)

function switchTo2d() {
  viewerRef.value?.switchMode?.('2d')
}

function switchTo3d() {
  viewerRef.value?.switchMode?.('3d')
}
</script>

<template>
  <div style="height: 100vh;">
    <button type="button" @click="switchTo2d">查看二维</button>
    <button type="button" @click="switchTo3d">查看三维</button>
    <LrMapViewer
      ref="viewerRef"
      :modes="['2d', '3d']"
      :map2d-config="map2dConfig"
      :lr3d-config="lr3dConfig"
    />
  </div>
</template>
```

模型信息查询回调返回结构：

```js
{
  // 模型或实体标识
  id: '...',
  // 模型或实体名称
  name: '...',
  // 所属图层名
  layerName: '...',
  position: {
    // 模型本地坐标 x
    x: 0,
    // 模型本地坐标 y
    y: 0,
    // 模型本地坐标 z
    z: 0,
  },
}
```

## 云 GIS 配置说明

推荐写法：

```js
const lr3dConfig = {
  autoLoad: true,
  cloud: {
    server: 'https://your-cloud-gis-server/',
    username: 'your_username',
    password: 'your_password',
    dsGuid: 'your_ds_guid',
    basePoint: {
      x: 37517614.46684,
      y: 4410289.679932,
      z: 972.148557,
    },
    layers: ['your_lane_layer_name'],
    laneSize: {
      width: 10,
      height: 10,
    },
  },
}
```

推荐接入方式同样分为两种：

- 通过 `credentialKey` 接入：
  组件会自动补齐 `cloud.server`、`cloud.username`、`cloud.password`，此时你通常只需要传 `autoLoad`、`cloud.dsGuid`、`cloud.basePoint` 以及业务图层参数。
- 不通过 `credentialKey`，直接手动传完整三维配置：
  需要自行补齐三维服务地址和认证信息。

手动直传完整三维配置时的必填字段：

- `autoLoad`
  是否在场景初始化成功后自动加载云 GIS 数据。
- `cloud.server`
  云 GIS 服务地址。
- `cloud.username`
  云 GIS 用户名。
- `cloud.password`
  云 GIS 密码。
- `cloud.dsGuid`
  数据源 guid。
- `cloud.basePoint.x`
  三维场景基点 x 坐标。
- `cloud.basePoint.y`
  三维场景基点 y 坐标。
- `cloud.basePoint.z`
  三维场景基点 z 坐标。

可选字段：

- `cloud.layers`
  需要加载的巷道图层名数组。
- `cloud.laneSize.width`
  巷道渲染宽度，默认 `10`
- `cloud.laneSize.height`
  巷道渲染高度，默认 `10`

兼容说明：

- 组件内部仍兼容完整的 `lr3dConfig` 写法。
- `basePoint` 推荐传入 `{ x, y, z }` 对象。
- `resource-prefix` 可用于统一给默认的 `/editorapp` 与 `/resource` 路径增加业务前缀，例如 `gkpt -> /gkpt/editorapp/...`、`/gkpt/resource/...`。
- 如果你需要覆盖 SDK 路径、容器参数、初始化参数等高级配置，仍然可以继续传入 `sdk`、`scene`、`initOptions`、`dataSource` 完整结构。

## 示例配置

下面这份三维配置可直接作为联调参考：

```js
const playgroundLr3dConfig = {
  autoLoad: true,
  cloud: {
    server: 'https://your-cloud-gis-server/',
    username: 'your_username',
    password: 'your_password',
    dsGuid: 'your_ds_guid',
    basePoint: {
      x: 37517614.46684,
      y: 4410289.679932,
      z: 972.148557,
    },
    layers: ['your_lane_layer_name'],
    laneSize: {
      width: 10,
      height: 10,
    },
  },
}
```

## 常见错误排查

### 1. 场景初始化失败：SDK 前置依赖加载失败

典型错误：

```text
场景初始化失败：SDK 前置依赖加载失败: /resource/js/jquery-3.1.1.min.js
```

排查方向：

1. 确认客户项目里确实存在 `public/resource/js/jquery-3.1.1.min.js`。
2. 确认浏览器访问 `/resource/js/jquery-3.1.1.min.js` 返回 200，而不是 404。
3. 如果资源目录不在根路径，使用完整 `lr3dConfig.sdk.dependencies` 配置覆盖默认脚本路径。
4. 确认 `editorapp` 与 `resource` 属于同一套 SDK 版本，不要混用不同批次文件。

### 2. 场景初始化失败：未检测到全局对象

这类错误通常表示脚本文件虽然加载了，但脚本执行后没有挂出预期全局变量。

排查方向：

1. 检查使用的 SDK 版本是否与组件默认配置匹配。
2. 检查脚本是否被浏览器拦截、跨域策略阻止，或返回了错误 HTML 页面。
3. 检查依赖加载顺序是否正确，前置依赖必须先于 `editorapp.bundle.js` 完成加载。

### 3. 云 GIS 数据源配置缺失

典型原因：

- 组件库默认配置已不再携带真实业务参数。
- 接入方没有传入 `server`、`username`、`password`、`dsGuid`、`basePoint`。

处理方式：

- 在 `lr3dConfig.cloud` 中补齐实际项目所需字段。
